question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

PostgreSQL partial_match not working in PageChooserPanel and SnippetChooserPanel

See original GitHub issue

We just updated to Wagtail 2.15.1 and updated to use new database search backend. Previously we have used wagtail.contrib.postgres_search.backend and partial match has never worked us, thus we have actually overridden search for PageChooserPanel and SnippetChooserPanel with our own implementation to make the search usable without using Elasticsearch. In the newest 2.15.1 there is no mention that partial match isn’t supported with PostgreSQL, so I assume there is a bug, or then documentation should be updated.

Issue Summary

We have an ArticlePage model which is using Wagtail’s default search_fields, for ‘title’ as following:

index.SearchField('title', partial_match=True, boost=2),
index.AutocompleteField('title'),

When trying to select ArticlePage using PageChooserPanel, search will not match partial words, for example page with title “Hello world” will only match with “Hello” or “world”, but not with “Hel”. The same is true for SnippetChooserPanel when selecting snippets. Autocomplete works, for example if there are “Hi world” and “Hello world” pages, searching “world” will show both pages immediately when “world” is written, but nothing with “worl” like expected.

To overcome this problem, we have patched Wagtail’s default search with our own search implementation, us such:

def search(search_query, items, model):
   """Search override for Wagtail's default search to support partial matching"""
   conditions = Q()
   for term in search_query.split():
       for field in model.search_fields:
           # Ensure only SearchFields are used for filtering
           if isinstance(field, index.SearchField):
               conditions |= Q(**{'%s__icontains' % field.field_name: term})
   return items.filter(conditions)

With that override, the search for PageChooserPanel and SnippetChooserPanel works as expected what comes to partial matching, but this doesn’t support other features like boost. Still, this gives us much better user experience, but we would like to get rid of our ugly hacks.

Maybe we are missing something or then PostgreSQL really doesn’t support partial matching. In either case, I feel like documentation should be improved to make it clear whether it works or how to make it work.

Technical details

  • Python version: Python 3.9.4
  • Django version: 3.2.6
  • Wagtail version: 2.15.1
  • Browser version: Safari 15

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:3
  • Comments:16 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
krukascommented, Jan 18, 2022

I was having the same issue and looks like this is happening because Lexeme prefix is False. The Lexeme prefix option is set by the class constant LAST_TERM_IS_PREFIX, and there is no option to change this behavior.

My dirty hack/fix:

from wagtail.search.backends.database.postgres.postgres import PostgresSearchQueryCompiler
PostgresSearchQueryCompiler.LAST_TERM_IS_PREFIX = True
1reaction
mikarauniocommented, Dec 5, 2022

@gasman Don’t really have an opinion either way on what the default should be, and your points in support of exact matching make a lot of sense to me. However, as someone who just lost an afternoon trying to figure this out before finding this issue, I’d like to reiterate @m5seppal’s original point that Wagtail’s default behavior really should be documented properly.

As it stands:

  • The default behaviour varies by backend: elasticsearch does partial matching while database doesn’t, yet this is documented nowhere
  • Instead, search/indexing.html creates the expectation that partial matching wil just work:

    “partial_match (boolean) - Setting this to true allows results to be matched on parts of words. For example, this is set on the title field by default, so a page titled Hello World! will be found if the user only types Hel into the search box.”

Read more comments on GitHub >

github_iconTop Results From Across the Web

Partial matching search in Wagtail with Postgres
We're currently rebuilding the Wagtail search API in order to make autocomplete usable roughly the same way across backends.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found