Elasticsearch/Kibana查询搜索的复数支持及匹配问题问询
好的,针对你遇到的这三个Elasticsearch查询问题,咱们可以直接在ES层面通过调整分词规则和查询策略来解决,完全不需要在应用层做复杂的语义分析或查询拼接,具体方案如下:
问题1:解决单复数不识别的问题
Elasticsearch默认的标准分词器不会处理单复数逻辑,咱们可以用内置的english分词器——它自带词干提取(stemming)功能,能自动把doctors这类复数形式还原成doctor。
你需要先删除原有的test索引,重新创建一个带有指定分词器的索引,再导入数据:
# 删除旧索引 DELETE /test # 创建新索引,指定字段使用english分词器 PUT /test { "mappings": { "properties": { "type": { "type": "text", "analyzer": "english" }, "name": { "type": "text" }, "works_in": { "type": "nested", "properties": { "place": { "type": "text", "analyzer": "english" } } } } } } # 重新导入三个文档 PUT /test/_doc/1 { "type": "doctor", "name": "Phil", "works_in": [ { "place": "Chicago" }, { "place": "New York" } ] } PUT /test/_doc/2 { "type": "lawyer", "name": "John", "works_in": [ { "place": "Chicago" }, { "place": "New Jersey" } ] } PUT /test/_doc/3 { "type": "doctor", "name": "Jill", "works_in": [ { "place": "Chicago" } ] }
现在再执行查询GET /test/_search { "query": { "multi_match" : { "query": "doctors in chicago", "fields": [ "type", "place" ] } } },就能正确匹配到所有type为doctor且在Chicago工作的文档了。
问题2:解决多字段OR匹配导致的误查询
默认的multi_match查询用的是best_fields类型,采用OR逻辑——只要任意字段匹配任意查询词就会返回结果。咱们可以把查询类型改成cross_fields,同时设置operator: "and",这样所有查询词都需要在指定的字段集合中出现(跨字段匹配),就能避免只匹配到doctor但没匹配到new york的结果。
调整后的查询语句如下:
GET /test/_search { "query": { "multi_match" : { "query": "doctor in new york", "fields": [ "type", "place" ], "type": "cross_fields", "operator": "and" } } }
解释一下:english分词器会自动过滤掉停用词in,所以实际查询词是doctor和new york;cross_fields类型会把多个字段当成一个大的字段来匹配,operator: "and"要求两个词都必须存在,这样就只会返回type为doctor且place包含New York的文档(也就是文档1),不会再返回芝加哥的医生了。
问题3:实现同义词映射
要让docs、physicians、health professionals这类词映射为doctor,咱们需要创建一个自定义分词器,添加同义词过滤器。同样需要重新创建索引:
DELETE /test PUT /test { "settings": { "analysis": { "filter": { "doctor_synonyms": { "type": "synonym", "synonyms": [ "docs, physicians, health professionals => doctor" ] } }, "analyzer": { "english_with_synonyms": { "tokenizer": "standard", "filter": [ "lowercase", "english_stop", "english_stemmer", "doctor_synonyms" ] } } } }, "mappings": { "properties": { "type": { "type": "text", "analyzer": "english_with_synonyms" }, "name": { "type": "text" }, "works_in": { "type": "nested", "properties": { "place": { "type": "text", "analyzer": "english" } } } } } } # 重新导入文档(同上,省略)
这里我们创建了一个名为english_with_synonyms的自定义分词器,它包含了同义词过滤器doctor_synonyms,把指定的同义词都映射为doctor。现在你查询physicians in chicago或者health professionals new york,都会正确匹配到对应的doctor文档。
额外提示
如果不想每次都重新创建索引,也可以在已有的索引上添加新的分词器和字段,但需要注意:已有的字段无法修改分词器配置,只能新增字段并重新同步数据,所以建议一开始就规划好分词规则。
内容的提问来源于stack exchange,提问作者JasonGenX

