现在有一个es的字段,希望它既能分词查询,又能有模糊查询怎么办?
只有分词查询的坏处:
可能单个字反而搜不出来,比如一个“南京”,搜“南”字就搜不出来,反而降低体验。
想让es既能分词又能模糊查询有几种办法:
方案一:利用 keyword 子字段实现精确与模糊搜索并存
实现原理
通过为 name 字段添加 keyword 子字段,使其既能进行分词搜索(利用 name 字段自身),又能实现精确或模糊搜索(借助 name.keyword 子字段)。
具体操作步骤
重新定义索引映射
PUT /ebox_material_bizitem/_mapping
{
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
搜索:
GET /ebox_material_bizitem/_search
{
"query": {
"bool": {
"should": [
{ "match": { "name": "四" } }, // 分词搜索(如:匹配"四川"、"四季")
{ "wildcard": { "name.keyword": "*四*" } } // 模糊搜索(需完整包含"四")
],
"minimum_should_match": 1
}
}
}
代码:
nameQuery := elastic.NewBoolQuery().
Should(
elastic.NewMatchQuery("name", req.GetName()), // 分词搜索
elastic.NewWildcardQuery("name.keyword", "*"+req.GetName()+"*"), // 模糊搜索
).
MinimumNumberShouldMatch(1)
queryArgs = append(queryArgs, es.WithMust(nameQuery))
方案二:运用自定义分词器实现多粒度分词
实现原理
创建一个自定义分词器,将文本同时分词为单字和词语,从而兼顾模糊搜索和分词搜索的需求。
方案三:结合 match 和 wildcard 查询
实现原理
在同一个查询中同时使用 match 查询(用于分词搜索)和 wildcard 查询(用于模糊搜索),然后通过 bool.should 将它们组合起来。
GET /ebox_material_bizitem/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"name": {
"query": "四",
"boost": 2 // 提高分词搜索的权重
}
}
},
{
"wildcard": {
"name": {
"value": "*四*",
"boost": 1 // 降低模糊搜索的权重
}
}
}
],
"minimum_should_match": 1
}
}
}
用代码实现:
if req.GetName() != "" {
nameQuery := elastic.NewBoolQuery().
Should(
elastic.NewMatchQuery("name", req.GetName()).Boost(2), // 提高分词搜索权重
elastic.NewWildcardQuery("name", "*"+req.GetName()+"*").Boost(1), // 降低模糊搜索权重
).
MinimumNumberShouldMatch(1)
queryArgs = append(queryArgs, es.WithMust(nameQuery))
}