Django ElasticSearch DSL使用nGram实现部分匹配无结果问题排查
问题原因
- 字段定义语法错误:
CategoryDocument类中title字段配置错误使用了冒号:而非等号=,属于Python类型注解语法,并未实际给title字段绑定自定义分词器,同时代码中存在重复导入analyzer和tokenizer模块的冗余问题 - 字段配置被覆盖:你在
Document类中单独定义了title字段的分词规则,却又把title放到了Django.fields列表中,django-elasticsearch-dsl会优先使用Django.fields里的字段配置,默认采用standard分词器,导致自定义的nGram分词器完全未生效 - 默认分词器拆分逻辑不匹配:standard分词器会把
T-Shirts拆分为t和shirts两个独立词条,搜索词T-Sh会被拆分为t和sh,sh和索引中的shirts无法匹配,只有输入到T-Shir时,fuzziness模糊匹配才会命中shirts词条,所以才会出现短搜索词无结果的问题
修复方案
第一步:修正shop/documents.py配置
from elasticsearch_dsl import analyzer, tokenizer, fields from django_elasticsearch_dsl import Document, registry from .models import Category autocomplete_analyzer = analyzer('autocomplete_analyzer', tokenizer=tokenizer('trigram', 'nGram', min_gram=2, max_gram=20), # 把min_gram改成2,避免生成太多单字符无效词条,减少索引体积 filter=['lowercase'] ) @registry.register_document class CategoryDocument(Document): # 把冒号改成等号,正确绑定字段配置 title = fields.TextField(analyzer=autocomplete_analyzer, search_analyzer='standard') class Index: name = 'categories' settings = { 'number_of_shards': 1, 'number_of_replicas': 0, 'max_ngram_diff': 20 } class Django: model = Category # 去掉已经在Document类中单独定义的title字段,避免覆盖配置 fields = [ # 其余需要索引的字段,title已单独配置无需写在这里 ]
第二步:重建Elasticsearch索引
修改配置后必须重建索引才能生效,执行以下命令:
python manage.py search_index --rebuild
第三步:(可选)优化查询逻辑
如果需要更精准的前缀短语匹配,可以给multi_match指定type为phrase_prefix,减少无关匹配:
class CategoryElasticSearch(ListView): def get(self, request, lang): search_term = request.GET.get('search_term', '').strip() q = Q( "multi_match", query=search_term, fields=[ 'title', # 其余需要搜索的字段 ], type="phrase_prefix", fuzziness='auto', ) search = search.query(q) # 其余逻辑
内容的提问来源于stack exchange,提问作者Michal Půlpán
相关产品推荐
相关产品推荐

