prompt: 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()
  
  ```
  
golden_diff: 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
  
verification_info: {"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"}]}