PostgreSQL partial_match not working in PageChooserPanel and SnippetChooserPanel
See original GitHub issueWe 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:
- Created 2 years ago
- Reactions:3
- Comments:16 (6 by maintainers)
Top GitHub Comments
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:
@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:
elasticsearch
does partial matching whiledatabase
doesn’t, yet this is documented nowheresearch/indexing.html
creates the expectation that partial matching wil just work: