We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Strange terms() behavior in IndexReaderUtils
I do this:

```
from pyserini.index import pyutils

index_utils = pyutils.IndexReaderUtils('lucene-index.robust04.pos+docvectors+rawdocs')

iter1 = index_utils.terms()
iter2 = index_utils.terms()

for term in iter1:
    print('{} (df={}, cf={})'.format(term.term, term.doc_freq, term.total_term_freq))
```

As expected, I iterate over all terms. Then:

```
for term in iter2:
    print('{} (df={}, cf={})'.format(term.term, term.doc_freq, term.total_term_freq))
```

Gives nothing... is `terms()` returning the same iterator every time?

Doesn't seem like the right behavior?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyserini/index/pyutils.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Pyserini: Python interface to the Anserini IR toolkit built on Lucene
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 '''
18 Module for providing python interface to Anserini index reader utils
19 '''
20 from ..pyclass import JIndexReaderUtils, JDocumentVectorWeight, JString
21 
22 import logging
23 
24 logger = logging.getLogger(__name__)
25 
26 
27 class IndexReaderUtils:
28     '''
29     Wrapper class for Anserini's IndexReaderUtils.
30 
31     Parameters
32     ----------
33     index_dir : str
34         Path to Lucene index directory
35     '''
36 
37     def __init__(self, index_dir):
38         self.object = JIndexReaderUtils()
39         self.reader = self.object.getReader(JString(index_dir))
40         self.term_iterator = self.object.getTerms(self.reader)
41 
42     class DocumentVectorWeight:
43         NONE = JDocumentVectorWeight.NONE
44         TF_IDF = JDocumentVectorWeight.TF_IDF
45 
46     class Posting:
47         '''
48         Basic Posting class for Postings List
49         '''
50         def __init__(self, docid, term_freq, positions):
51             self.docid = docid
52             self.term_freq = term_freq
53             self.positions = positions
54 
55         def __repr__(self):
56             repr = '(' + str(self.docid) + ', ' + str(self.term_freq) + ')'
57             if self.positions:
58                 repr += ' [' + ','.join([str(p) for p in self.positions]) + ']'
59             return repr
60 
61     class IndexTerm:
62         '''
63         Basic IndexTerm class to represent each term in index
64         '''
65         def __init__(self, term, doc_freq, total_term_freq):
66             self.term = term
67             self.doc_freq = doc_freq
68             self.total_term_freq = total_term_freq
69 
70     def analyze_term(self, term):
71         '''
72         Parameters
73         ----------
74         term : str
75         Returns
76         -------
77         result : str
78             Stemmed term
79         '''
80         return self.object.analyzeTerm(JString(term))
81 
82     def terms(self):
83         '''
84         :return: generator over terms
85         '''
86         while self.term_iterator.hasNext():
87             cur_term = self.term_iterator.next()
88             yield self.IndexTerm(cur_term.getTerm(), cur_term.getDF(), cur_term.getTotalTF())
89 
90     def get_term_counts(self, term):
91         '''
92         Parameters
93         ----------
94         term : str
95             Raw term
96         Returns
97         -------
98         result : long, long
99             Collection frequency and document frequency of term
100         '''
101         term_map = self.object.getTermCounts(self.reader, JString(term))
102         return term_map.get(JString('collectionFreq')), term_map.get(JString('docFreq'))
103 
104     def get_postings_list(self, term):
105         '''
106         Parameters
107         ----------
108         term : str
109         Returns
110         -------
111         result : list<Posting>
112             Postings list for term
113         '''
114         postings_list = self.object.getPostingsList(self.reader, JString(term))
115         result = []
116         for posting in postings_list.toArray():
117             result.append(self.Posting(posting.getDocid(), posting.getTF(), posting.getPositions()))
118         return result
119 
120     def get_document_vector(self, docid):
121         '''
122         Parameters
123         ----------
124         docid : str
125             Collection docid
126         Returns
127         -------
128         result : dict
129             Terms and their respective frequencies in document
130         '''
131         doc_vector_map = self.object.getDocumentVector(self.reader, JString(docid))
132         doc_vector_dict = {}
133         for term in doc_vector_map.keySet().toArray():
134             doc_vector_dict[term] = doc_vector_map.get(JString(term))
135         return doc_vector_dict
136 
137     def get_bm25_term_weight(self, docid, term):
138         '''
139         Parameters
140         ----------
141         docid : str
142             Collection docid
143         term : str
144         Returns
145         -------
146         result : float
147             BM25 score (NaN if no documents match)
148         '''
149         return self.object.getBM25TermWeight(self.reader, JString(docid), JString(term))
150 
151     def dump_document_vectors(self, reqDocidsPath, weight):
152         '''
153         Parameters
154         ----------
155         reqDocidsPath : str
156             dumps the document vector for all documents in reqDocidsPath
157         weight : DocumentVectorWeight
158             the weight for dumped document vector(s)
159         '''
160         self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)
161
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyserini/index/pyutils.py b/pyserini/index/pyutils.py
--- a/pyserini/index/pyutils.py
+++ b/pyserini/index/pyutils.py
@@ -37,7 +37,6 @@
     def __init__(self, index_dir):
         self.object = JIndexReaderUtils()
         self.reader = self.object.getReader(JString(index_dir))
-        self.term_iterator = self.object.getTerms(self.reader)
 
     class DocumentVectorWeight:
         NONE = JDocumentVectorWeight.NONE
@@ -83,8 +82,9 @@
         '''
         :return: generator over terms
         '''
-        while self.term_iterator.hasNext():
-            cur_term = self.term_iterator.next()
+        term_iterator = self.object.getTerms(self.reader)
+        while term_iterator.hasNext():
+            cur_term = term_iterator.next()
             yield self.IndexTerm(cur_term.getTerm(), cur_term.getDF(), cur_term.getTotalTF())
 
     def get_term_counts(self, term):
@@ -157,4 +157,4 @@
         weight : DocumentVectorWeight
             the weight for dumped document vector(s)
         '''
-        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)
+        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)
\ No newline at end of file

{"golden_diff": "diff --git a/pyserini/index/pyutils.py b/pyserini/index/pyutils.py\n--- a/pyserini/index/pyutils.py\n+++ b/pyserini/index/pyutils.py\n@@ -37,7 +37,6 @@\n     def __init__(self, index_dir):\n         self.object = JIndexReaderUtils()\n         self.reader = self.object.getReader(JString(index_dir))\n-        self.term_iterator = self.object.getTerms(self.reader)\n \n     class DocumentVectorWeight:\n         NONE = JDocumentVectorWeight.NONE\n@@ -83,8 +82,9 @@\n         '''\n         :return: generator over terms\n         '''\n-        while self.term_iterator.hasNext():\n-            cur_term = self.term_iterator.next()\n+        term_iterator = self.object.getTerms(self.reader)\n+        while term_iterator.hasNext():\n+            cur_term = term_iterator.next()\n             yield self.IndexTerm(cur_term.getTerm(), cur_term.getDF(), cur_term.getTotalTF())\n \n     def get_term_counts(self, term):\n@@ -157,4 +157,4 @@\n         weight : DocumentVectorWeight\n             the weight for dumped document vector(s)\n         '''\n-        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)\n+        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)\n\\ No newline at end of file\n", "issue": "Strange terms() behavior in IndexReaderUtils\nI do this:\r\n\r\n```\r\nfrom pyserini.index import pyutils\r\n\r\nindex_utils = pyutils.IndexReaderUtils('lucene-index.robust04.pos+docvectors+rawdocs')\r\n\r\niter1 = index_utils.terms()\r\niter2 = index_utils.terms()\r\n\r\nfor term in iter1:\r\n    print('{} (df={}, cf={})'.format(term.term, term.doc_freq, term.total_term_freq))\r\n```\r\n\r\nAs expected, I iterate over all terms. Then:\r\n\r\n```\r\nfor term in iter2:\r\n    print('{} (df={}, cf={})'.format(term.term, term.doc_freq, term.total_term_freq))\r\n```\r\n\r\nGives nothing... is `terms()` returning the same iterator every time?\r\n\r\nDoesn't seem like the right behavior?\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Pyserini: Python interface to the Anserini IR toolkit built on Lucene\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n'''\nModule for providing python interface to Anserini index reader utils\n'''\nfrom ..pyclass import JIndexReaderUtils, JDocumentVectorWeight, JString\n\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass IndexReaderUtils:\n    '''\n    Wrapper class for Anserini's IndexReaderUtils.\n\n    Parameters\n    ----------\n    index_dir : str\n        Path to Lucene index directory\n    '''\n\n    def __init__(self, index_dir):\n        self.object = JIndexReaderUtils()\n        self.reader = self.object.getReader(JString(index_dir))\n        self.term_iterator = self.object.getTerms(self.reader)\n\n    class DocumentVectorWeight:\n        NONE = JDocumentVectorWeight.NONE\n        TF_IDF = JDocumentVectorWeight.TF_IDF\n\n    class Posting:\n        '''\n        Basic Posting class for Postings List\n        '''\n        def __init__(self, docid, term_freq, positions):\n            self.docid = docid\n            self.term_freq = term_freq\n            self.positions = positions\n\n        def __repr__(self):\n            repr = '(' + str(self.docid) + ', ' + str(self.term_freq) + ')'\n            if self.positions:\n                repr += ' [' + ','.join([str(p) for p in self.positions]) + ']'\n            return repr\n\n    class IndexTerm:\n        '''\n        Basic IndexTerm class to represent each term in index\n        '''\n        def __init__(self, term, doc_freq, total_term_freq):\n            self.term = term\n            self.doc_freq = doc_freq\n            self.total_term_freq = total_term_freq\n\n    def analyze_term(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n        Returns\n        -------\n        result : str\n            Stemmed term\n        '''\n        return self.object.analyzeTerm(JString(term))\n\n    def terms(self):\n        '''\n        :return: generator over terms\n        '''\n        while self.term_iterator.hasNext():\n            cur_term = self.term_iterator.next()\n            yield self.IndexTerm(cur_term.getTerm(), cur_term.getDF(), cur_term.getTotalTF())\n\n    def get_term_counts(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n            Raw term\n        Returns\n        -------\n        result : long, long\n            Collection frequency and document frequency of term\n        '''\n        term_map = self.object.getTermCounts(self.reader, JString(term))\n        return term_map.get(JString('collectionFreq')), term_map.get(JString('docFreq'))\n\n    def get_postings_list(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n        Returns\n        -------\n        result : list<Posting>\n            Postings list for term\n        '''\n        postings_list = self.object.getPostingsList(self.reader, JString(term))\n        result = []\n        for posting in postings_list.toArray():\n            result.append(self.Posting(posting.getDocid(), posting.getTF(), posting.getPositions()))\n        return result\n\n    def get_document_vector(self, docid):\n        '''\n        Parameters\n        ----------\n        docid : str\n            Collection docid\n        Returns\n        -------\n        result : dict\n            Terms and their respective frequencies in document\n        '''\n        doc_vector_map = self.object.getDocumentVector(self.reader, JString(docid))\n        doc_vector_dict = {}\n        for term in doc_vector_map.keySet().toArray():\n            doc_vector_dict[term] = doc_vector_map.get(JString(term))\n        return doc_vector_dict\n\n    def get_bm25_term_weight(self, docid, term):\n        '''\n        Parameters\n        ----------\n        docid : str\n            Collection docid\n        term : str\n        Returns\n        -------\n        result : float\n            BM25 score (NaN if no documents match)\n        '''\n        return self.object.getBM25TermWeight(self.reader, JString(docid), JString(term))\n\n    def dump_document_vectors(self, reqDocidsPath, weight):\n        '''\n        Parameters\n        ----------\n        reqDocidsPath : str\n            dumps the document vector for all documents in reqDocidsPath\n        weight : DocumentVectorWeight\n            the weight for dumped document vector(s)\n        '''\n        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)\n", "path": "pyserini/index/pyutils.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Pyserini: Python interface to the Anserini IR toolkit built on Lucene\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n'''\nModule for providing python interface to Anserini index reader utils\n'''\nfrom ..pyclass import JIndexReaderUtils, JDocumentVectorWeight, JString\n\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass IndexReaderUtils:\n    '''\n    Wrapper class for Anserini's IndexReaderUtils.\n\n    Parameters\n    ----------\n    index_dir : str\n        Path to Lucene index directory\n    '''\n\n    def __init__(self, index_dir):\n        self.object = JIndexReaderUtils()\n        self.reader = self.object.getReader(JString(index_dir))\n\n    class DocumentVectorWeight:\n        NONE = JDocumentVectorWeight.NONE\n        TF_IDF = JDocumentVectorWeight.TF_IDF\n\n    class Posting:\n        '''\n        Basic Posting class for Postings List\n        '''\n        def __init__(self, docid, term_freq, positions):\n            self.docid = docid\n            self.term_freq = term_freq\n            self.positions = positions\n\n        def __repr__(self):\n            repr = '(' + str(self.docid) + ', ' + str(self.term_freq) + ')'\n            if self.positions:\n                repr += ' [' + ','.join([str(p) for p in self.positions]) + ']'\n            return repr\n\n    class IndexTerm:\n        '''\n        Basic IndexTerm class to represent each term in index\n        '''\n        def __init__(self, term, doc_freq, total_term_freq):\n            self.term = term\n            self.doc_freq = doc_freq\n            self.total_term_freq = total_term_freq\n\n    def analyze_term(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n        Returns\n        -------\n        result : str\n            Stemmed term\n        '''\n        return self.object.analyzeTerm(JString(term))\n\n    def terms(self):\n        '''\n        :return: generator over terms\n        '''\n        term_iterator = self.object.getTerms(self.reader)\n        while term_iterator.hasNext():\n            cur_term = term_iterator.next()\n            yield self.IndexTerm(cur_term.getTerm(), cur_term.getDF(), cur_term.getTotalTF())\n\n    def get_term_counts(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n            Raw term\n        Returns\n        -------\n        result : long, long\n            Collection frequency and document frequency of term\n        '''\n        term_map = self.object.getTermCounts(self.reader, JString(term))\n        return term_map.get(JString('collectionFreq')), term_map.get(JString('docFreq'))\n\n    def get_postings_list(self, term):\n        '''\n        Parameters\n        ----------\n        term : str\n        Returns\n        -------\n        result : list<Posting>\n            Postings list for term\n        '''\n        postings_list = self.object.getPostingsList(self.reader, JString(term))\n        result = []\n        for posting in postings_list.toArray():\n            result.append(self.Posting(posting.getDocid(), posting.getTF(), posting.getPositions()))\n        return result\n\n    def get_document_vector(self, docid):\n        '''\n        Parameters\n        ----------\n        docid : str\n            Collection docid\n        Returns\n        -------\n        result : dict\n            Terms and their respective frequencies in document\n        '''\n        doc_vector_map = self.object.getDocumentVector(self.reader, JString(docid))\n        doc_vector_dict = {}\n        for term in doc_vector_map.keySet().toArray():\n            doc_vector_dict[term] = doc_vector_map.get(JString(term))\n        return doc_vector_dict\n\n    def get_bm25_term_weight(self, docid, term):\n        '''\n        Parameters\n        ----------\n        docid : str\n            Collection docid\n        term : str\n        Returns\n        -------\n        result : float\n            BM25 score (NaN if no documents match)\n        '''\n        return self.object.getBM25TermWeight(self.reader, JString(docid), JString(term))\n\n    def dump_document_vectors(self, reqDocidsPath, weight):\n        '''\n        Parameters\n        ----------\n        reqDocidsPath : str\n            dumps the document vector for all documents in reqDocidsPath\n        weight : DocumentVectorWeight\n            the weight for dumped document vector(s)\n        '''\n        self.object.dumpDocumentVectors(self.reader, reqDocidsPath, weight)", "path": "pyserini/index/pyutils.py"}]}