prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Subject tag autocomplete no longer sorts by frequency
  When I developed autocomplete for subject tags, the results returned were automatically sorted by frequency — the most used subjects that matched were first on the list. This not only produced useful results, but helped concentrate the usage of particular subjects where multiple similar labels exist for a single topic, improving the quality of subject pages.
  
  In subsequent refactoring of autocomplete support, this frequency sorting was lost.
  
  ### Steps to Reproduce
  Edit a work and start typing in one of the subject fields to display the list of matching subjects.
  
  <!-- What actually happened after these steps? What did you expect to happen? -->
  * Actual: Subject suggestions are sorted in an apparently random order
  * Expected: Subjects should be sorted with the "better" (more frequently used) choices at the top.
  
  ### Proposal & Constraints
  I will be submitting a PR that restores the SOLR query that produces the frequency-sorted results.
  
  ### Stakeholders
  @mheiman @cdrini 
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `openlibrary/plugins/worksearch/autocomplete.py`
  Content:
  ```
  1 import itertools
  2 import web
  3 import json
  4 
  5 
  6 from infogami.utils import delegate
  7 from infogami.utils.view import safeint
  8 from openlibrary.core.models import Thing
  9 from openlibrary.plugins.upstream import utils
  10 from openlibrary.plugins.worksearch.search import get_solr
  11 from openlibrary.utils import (
  12     find_olid_in_string,
  13     olid_to_key,
  14 )
  15 
  16 
  17 def to_json(d):
  18     web.header('Content-Type', 'application/json')
  19     return delegate.RawText(json.dumps(d))
  20 
  21 
  22 class autocomplete(delegate.page):
  23     path = "/_autocomplete"
  24     fq = ['-type:edition']
  25     fl = 'key,type,name,title,score'
  26     olid_suffix: str | None = None
  27     query = 'title:"{q}"^2 OR title:({q}*) OR name:"{q}"^2 OR name:({q}*)'
  28 
  29     def db_fetch(self, key: str) -> Thing | None:
  30         if thing := web.ctx.site.get(key):
  31             return thing.as_fake_solr_record()
  32         else:
  33             return None
  34 
  35     def doc_wrap(self, doc: dict):
  36         """Modify the returned solr document in place."""
  37         if 'name' not in doc:
  38             doc['name'] = doc.get('title')
  39 
  40     def doc_filter(self, doc: dict) -> bool:
  41         """Exclude certain documents"""
  42         return True
  43 
  44     def GET(self):
  45         return self.direct_get()
  46 
  47     def direct_get(self, fq: list[str] | None = None):
  48         i = web.input(q="", limit=5)
  49         i.limit = safeint(i.limit, 5)
  50 
  51         solr = get_solr()
  52 
  53         # look for ID in query string here
  54         q = solr.escape(i.q).strip()
  55         embedded_olid = None
  56         if self.olid_suffix:
  57             embedded_olid = find_olid_in_string(q, self.olid_suffix)
  58 
  59         if embedded_olid:
  60             solr_q = f'key:"{olid_to_key(embedded_olid)}"'
  61         else:
  62             solr_q = self.query.format(q=q)
  63 
  64         fq = fq or self.fq
  65         params = {
  66             'q_op': 'AND',
  67             'rows': i.limit,
  68             **({'fq': fq} if fq else {}),
  69             # limit the fields returned for better performance
  70             'fl': self.fl,
  71         }
  72 
  73         data = solr.select(solr_q, **params)
  74         docs = data['docs']
  75 
  76         if embedded_olid and not docs:
  77             # Grumble! Work not in solr yet. Create a dummy.
  78             fake_doc = self.db_fetch(olid_to_key(embedded_olid))
  79             if fake_doc:
  80                 docs = [fake_doc]
  81 
  82         result_docs = []
  83         for d in docs:
  84             if self.doc_filter(d):
  85                 self.doc_wrap(d)
  86                 result_docs.append(d)
  87 
  88         return to_json(result_docs)
  89 
  90 
  91 class languages_autocomplete(delegate.page):
  92     path = "/languages/_autocomplete"
  93 
  94     def GET(self):
  95         i = web.input(q="", limit=5)
  96         i.limit = safeint(i.limit, 5)
  97         return to_json(
  98             list(itertools.islice(utils.autocomplete_languages(i.q), i.limit))
  99         )
  100 
  101 
  102 class works_autocomplete(autocomplete):
  103     path = "/works/_autocomplete"
  104     fq = ['type:work']
  105     fl = 'key,title,subtitle,cover_i,first_publish_year,author_name,edition_count'
  106     olid_suffix = 'W'
  107     query = 'title:"{q}"^2 OR title:({q}*)'
  108 
  109     def doc_filter(self, doc: dict) -> bool:
  110         # Exclude orphaned editions from autocomplete results
  111         # Note: Do this here instead of with an `fq=key:*W` for performance
  112         # reasons.
  113         return doc['key'][-1] == 'W'
  114 
  115     def doc_wrap(self, doc: dict):
  116         doc['full_title'] = doc['title']
  117         if 'subtitle' in doc:
  118             doc['full_title'] += ": " + doc['subtitle']
  119         doc['name'] = doc.get('title')
  120 
  121 
  122 class authors_autocomplete(autocomplete):
  123     path = "/authors/_autocomplete"
  124     fq = ['type:author']
  125     fl = 'key,name,alternate_names,birth_date,death_date,work_count,top_work,top_subjects'
  126     olid_suffix = 'A'
  127     query = 'name:({q}*) OR alternate_names:({q}*) OR name:"{q}"^2 OR alternate_names:"{q}"^2'
  128 
  129     def doc_wrap(self, doc: dict):
  130         if 'top_work' in doc:
  131             doc['works'] = [doc.pop('top_work')]
  132         else:
  133             doc['works'] = []
  134         doc['subjects'] = doc.pop('top_subjects', [])
  135 
  136 
  137 class subjects_autocomplete(autocomplete):
  138     # can't use /subjects/_autocomplete because the subjects endpoint = /subjects/[^/]+
  139     path = "/subjects_autocomplete"
  140     fq = ['type:subject']
  141     fl = 'key,name'
  142     query = 'name:({q}*)'
  143 
  144     def GET(self):
  145         i = web.input(type="")
  146         fq = self.fq
  147         if i.type:
  148             fq = fq + [f'subject_type:{i.type}']
  149 
  150         return super().direct_get(fq=fq)
  151 
  152 
  153 def setup():
  154     """Do required setup."""
  155     pass
  156
  ```
  --- 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/openlibrary/plugins/worksearch/autocomplete.py b/openlibrary/plugins/worksearch/autocomplete.py
  --- a/openlibrary/plugins/worksearch/autocomplete.py
  +++ b/openlibrary/plugins/worksearch/autocomplete.py
  @@ -24,6 +24,7 @@
       fq = ['-type:edition']
       fl = 'key,type,name,title,score'
       olid_suffix: str | None = None
  +    sort: str | None = None
       query = 'title:"{q}"^2 OR title:({q}*) OR name:"{q}"^2 OR name:({q}*)'
   
       def db_fetch(self, key: str) -> Thing | None:
  @@ -68,6 +69,7 @@
               **({'fq': fq} if fq else {}),
               # limit the fields returned for better performance
               'fl': self.fl,
  +            **({'sort': self.sort} if self.sort else {}),
           }
   
           data = solr.select(solr_q, **params)
  @@ -138,8 +140,9 @@
       # can't use /subjects/_autocomplete because the subjects endpoint = /subjects/[^/]+
       path = "/subjects_autocomplete"
       fq = ['type:subject']
  -    fl = 'key,name'
  +    fl = 'key,name,work_count'
       query = 'name:({q}*)'
  +    sort = 'work_count desc'
   
       def GET(self):
           i = web.input(type="")
  
verification_info: {"golden_diff": "diff --git a/openlibrary/plugins/worksearch/autocomplete.py b/openlibrary/plugins/worksearch/autocomplete.py\n--- a/openlibrary/plugins/worksearch/autocomplete.py\n+++ b/openlibrary/plugins/worksearch/autocomplete.py\n@@ -24,6 +24,7 @@\n     fq = ['-type:edition']\n     fl = 'key,type,name,title,score'\n     olid_suffix: str | None = None\n+    sort: str | None = None\n     query = 'title:\"{q}\"^2 OR title:({q}*) OR name:\"{q}\"^2 OR name:({q}*)'\n \n     def db_fetch(self, key: str) -> Thing | None:\n@@ -68,6 +69,7 @@\n             **({'fq': fq} if fq else {}),\n             # limit the fields returned for better performance\n             'fl': self.fl,\n+            **({'sort': self.sort} if self.sort else {}),\n         }\n \n         data = solr.select(solr_q, **params)\n@@ -138,8 +140,9 @@\n     # can't use /subjects/_autocomplete because the subjects endpoint = /subjects/[^/]+\n     path = \"/subjects_autocomplete\"\n     fq = ['type:subject']\n-    fl = 'key,name'\n+    fl = 'key,name,work_count'\n     query = 'name:({q}*)'\n+    sort = 'work_count desc'\n \n     def GET(self):\n         i = web.input(type=\"\")\n", "issue": "Subject tag autocomplete no longer sorts by frequency\nWhen I developed autocomplete for subject tags, the results returned were automatically sorted by frequency \u2014 the most used subjects that matched were first on the list. This not only produced useful results, but helped concentrate the usage of particular subjects where multiple similar labels exist for a single topic, improving the quality of subject pages.\r\n\r\nIn subsequent refactoring of autocomplete support, this frequency sorting was lost.\r\n\r\n### Steps to Reproduce\r\nEdit a work and start typing in one of the subject fields to display the list of matching subjects.\r\n\r\n<!-- What actually happened after these steps? What did you expect to happen? -->\r\n* Actual: Subject suggestions are sorted in an apparently random order\r\n* Expected: Subjects should be sorted with the \"better\" (more frequently used) choices at the top.\r\n\r\n### Proposal & Constraints\r\nI will be submitting a PR that restores the SOLR query that produces the frequency-sorted results.\r\n\r\n### Stakeholders\r\n@mheiman @cdrini \r\n\n", "before_files": [{"content": "import itertools\nimport web\nimport json\n\n\nfrom infogami.utils import delegate\nfrom infogami.utils.view import safeint\nfrom openlibrary.core.models import Thing\nfrom openlibrary.plugins.upstream import utils\nfrom openlibrary.plugins.worksearch.search import get_solr\nfrom openlibrary.utils import (\n    find_olid_in_string,\n    olid_to_key,\n)\n\n\ndef to_json(d):\n    web.header('Content-Type', 'application/json')\n    return delegate.RawText(json.dumps(d))\n\n\nclass autocomplete(delegate.page):\n    path = \"/_autocomplete\"\n    fq = ['-type:edition']\n    fl = 'key,type,name,title,score'\n    olid_suffix: str | None = None\n    query = 'title:\"{q}\"^2 OR title:({q}*) OR name:\"{q}\"^2 OR name:({q}*)'\n\n    def db_fetch(self, key: str) -> Thing | None:\n        if thing := web.ctx.site.get(key):\n            return thing.as_fake_solr_record()\n        else:\n            return None\n\n    def doc_wrap(self, doc: dict):\n        \"\"\"Modify the returned solr document in place.\"\"\"\n        if 'name' not in doc:\n            doc['name'] = doc.get('title')\n\n    def doc_filter(self, doc: dict) -> bool:\n        \"\"\"Exclude certain documents\"\"\"\n        return True\n\n    def GET(self):\n        return self.direct_get()\n\n    def direct_get(self, fq: list[str] | None = None):\n        i = web.input(q=\"\", limit=5)\n        i.limit = safeint(i.limit, 5)\n\n        solr = get_solr()\n\n        # look for ID in query string here\n        q = solr.escape(i.q).strip()\n        embedded_olid = None\n        if self.olid_suffix:\n            embedded_olid = find_olid_in_string(q, self.olid_suffix)\n\n        if embedded_olid:\n            solr_q = f'key:\"{olid_to_key(embedded_olid)}\"'\n        else:\n            solr_q = self.query.format(q=q)\n\n        fq = fq or self.fq\n        params = {\n            'q_op': 'AND',\n            'rows': i.limit,\n            **({'fq': fq} if fq else {}),\n            # limit the fields returned for better performance\n            'fl': self.fl,\n        }\n\n        data = solr.select(solr_q, **params)\n        docs = data['docs']\n\n        if embedded_olid and not docs:\n            # Grumble! Work not in solr yet. Create a dummy.\n            fake_doc = self.db_fetch(olid_to_key(embedded_olid))\n            if fake_doc:\n                docs = [fake_doc]\n\n        result_docs = []\n        for d in docs:\n            if self.doc_filter(d):\n                self.doc_wrap(d)\n                result_docs.append(d)\n\n        return to_json(result_docs)\n\n\nclass languages_autocomplete(delegate.page):\n    path = \"/languages/_autocomplete\"\n\n    def GET(self):\n        i = web.input(q=\"\", limit=5)\n        i.limit = safeint(i.limit, 5)\n        return to_json(\n            list(itertools.islice(utils.autocomplete_languages(i.q), i.limit))\n        )\n\n\nclass works_autocomplete(autocomplete):\n    path = \"/works/_autocomplete\"\n    fq = ['type:work']\n    fl = 'key,title,subtitle,cover_i,first_publish_year,author_name,edition_count'\n    olid_suffix = 'W'\n    query = 'title:\"{q}\"^2 OR title:({q}*)'\n\n    def doc_filter(self, doc: dict) -> bool:\n        # Exclude orphaned editions from autocomplete results\n        # Note: Do this here instead of with an `fq=key:*W` for performance\n        # reasons.\n        return doc['key'][-1] == 'W'\n\n    def doc_wrap(self, doc: dict):\n        doc['full_title'] = doc['title']\n        if 'subtitle' in doc:\n            doc['full_title'] += \": \" + doc['subtitle']\n        doc['name'] = doc.get('title')\n\n\nclass authors_autocomplete(autocomplete):\n    path = \"/authors/_autocomplete\"\n    fq = ['type:author']\n    fl = 'key,name,alternate_names,birth_date,death_date,work_count,top_work,top_subjects'\n    olid_suffix = 'A'\n    query = 'name:({q}*) OR alternate_names:({q}*) OR name:\"{q}\"^2 OR alternate_names:\"{q}\"^2'\n\n    def doc_wrap(self, doc: dict):\n        if 'top_work' in doc:\n            doc['works'] = [doc.pop('top_work')]\n        else:\n            doc['works'] = []\n        doc['subjects'] = doc.pop('top_subjects', [])\n\n\nclass subjects_autocomplete(autocomplete):\n    # can't use /subjects/_autocomplete because the subjects endpoint = /subjects/[^/]+\n    path = \"/subjects_autocomplete\"\n    fq = ['type:subject']\n    fl = 'key,name'\n    query = 'name:({q}*)'\n\n    def GET(self):\n        i = web.input(type=\"\")\n        fq = self.fq\n        if i.type:\n            fq = fq + [f'subject_type:{i.type}']\n\n        return super().direct_get(fq=fq)\n\n\ndef setup():\n    \"\"\"Do required setup.\"\"\"\n    pass\n", "path": "openlibrary/plugins/worksearch/autocomplete.py"}], "after_files": [{"content": "import itertools\nimport web\nimport json\n\n\nfrom infogami.utils import delegate\nfrom infogami.utils.view import safeint\nfrom openlibrary.core.models import Thing\nfrom openlibrary.plugins.upstream import utils\nfrom openlibrary.plugins.worksearch.search import get_solr\nfrom openlibrary.utils import (\n    find_olid_in_string,\n    olid_to_key,\n)\n\n\ndef to_json(d):\n    web.header('Content-Type', 'application/json')\n    return delegate.RawText(json.dumps(d))\n\n\nclass autocomplete(delegate.page):\n    path = \"/_autocomplete\"\n    fq = ['-type:edition']\n    fl = 'key,type,name,title,score'\n    olid_suffix: str | None = None\n    sort: str | None = None\n    query = 'title:\"{q}\"^2 OR title:({q}*) OR name:\"{q}\"^2 OR name:({q}*)'\n\n    def db_fetch(self, key: str) -> Thing | None:\n        if thing := web.ctx.site.get(key):\n            return thing.as_fake_solr_record()\n        else:\n            return None\n\n    def doc_wrap(self, doc: dict):\n        \"\"\"Modify the returned solr document in place.\"\"\"\n        if 'name' not in doc:\n            doc['name'] = doc.get('title')\n\n    def doc_filter(self, doc: dict) -> bool:\n        \"\"\"Exclude certain documents\"\"\"\n        return True\n\n    def GET(self):\n        return self.direct_get()\n\n    def direct_get(self, fq: list[str] | None = None):\n        i = web.input(q=\"\", limit=5)\n        i.limit = safeint(i.limit, 5)\n\n        solr = get_solr()\n\n        # look for ID in query string here\n        q = solr.escape(i.q).strip()\n        embedded_olid = None\n        if self.olid_suffix:\n            embedded_olid = find_olid_in_string(q, self.olid_suffix)\n\n        if embedded_olid:\n            solr_q = f'key:\"{olid_to_key(embedded_olid)}\"'\n        else:\n            solr_q = self.query.format(q=q)\n\n        fq = fq or self.fq\n        params = {\n            'q_op': 'AND',\n            'rows': i.limit,\n            **({'fq': fq} if fq else {}),\n            # limit the fields returned for better performance\n            'fl': self.fl,\n            **({'sort': self.sort} if self.sort else {}),\n        }\n\n        data = solr.select(solr_q, **params)\n        docs = data['docs']\n\n        if embedded_olid and not docs:\n            # Grumble! Work not in solr yet. Create a dummy.\n            fake_doc = self.db_fetch(olid_to_key(embedded_olid))\n            if fake_doc:\n                docs = [fake_doc]\n\n        result_docs = []\n        for d in docs:\n            if self.doc_filter(d):\n                self.doc_wrap(d)\n                result_docs.append(d)\n\n        return to_json(result_docs)\n\n\nclass languages_autocomplete(delegate.page):\n    path = \"/languages/_autocomplete\"\n\n    def GET(self):\n        i = web.input(q=\"\", limit=5)\n        i.limit = safeint(i.limit, 5)\n        return to_json(\n            list(itertools.islice(utils.autocomplete_languages(i.q), i.limit))\n        )\n\n\nclass works_autocomplete(autocomplete):\n    path = \"/works/_autocomplete\"\n    fq = ['type:work']\n    fl = 'key,title,subtitle,cover_i,first_publish_year,author_name,edition_count'\n    olid_suffix = 'W'\n    query = 'title:\"{q}\"^2 OR title:({q}*)'\n\n    def doc_filter(self, doc: dict) -> bool:\n        # Exclude orphaned editions from autocomplete results\n        # Note: Do this here instead of with an `fq=key:*W` for performance\n        # reasons.\n        return doc['key'][-1] == 'W'\n\n    def doc_wrap(self, doc: dict):\n        doc['full_title'] = doc['title']\n        if 'subtitle' in doc:\n            doc['full_title'] += \": \" + doc['subtitle']\n        doc['name'] = doc.get('title')\n\n\nclass authors_autocomplete(autocomplete):\n    path = \"/authors/_autocomplete\"\n    fq = ['type:author']\n    fl = 'key,name,alternate_names,birth_date,death_date,work_count,top_work,top_subjects'\n    olid_suffix = 'A'\n    query = 'name:({q}*) OR alternate_names:({q}*) OR name:\"{q}\"^2 OR alternate_names:\"{q}\"^2'\n\n    def doc_wrap(self, doc: dict):\n        if 'top_work' in doc:\n            doc['works'] = [doc.pop('top_work')]\n        else:\n            doc['works'] = []\n        doc['subjects'] = doc.pop('top_subjects', [])\n\n\nclass subjects_autocomplete(autocomplete):\n    # can't use /subjects/_autocomplete because the subjects endpoint = /subjects/[^/]+\n    path = \"/subjects_autocomplete\"\n    fq = ['type:subject']\n    fl = 'key,name,work_count'\n    query = 'name:({q}*)'\n    sort = 'work_count desc'\n\n    def GET(self):\n        i = web.input(type=\"\")\n        fq = self.fq\n        if i.type:\n            fq = fq + [f'subject_type:{i.type}']\n\n        return super().direct_get(fq=fq)\n\n\ndef setup():\n    \"\"\"Do required setup.\"\"\"\n    pass\n", "path": "openlibrary/plugins/worksearch/autocomplete.py"}]}