问题描述:
我们都知道ES针对复杂的多添加组合查询非常强大,也知道通过match可以实现全文检索查询(分词查询),但是如果现在我只需要实现类似mysql中的like全匹配模糊查询,该怎么实现呢?
业务场景:
从content_index表中查询字段content中包含ES的记录。
在关系型数据库中对应的SQL语句:
SELECT content FROM content_index WHERE content like '%ES%'
数据准备:
## 删除索引 ## DELETE content_index ## 新建索引 PUT content_index { "mappings": { "properties": { "content": { "type": "wildcard" } } } } ## 添加数据 POST content_index/_bulk?refresh { "create": { } } { "content": "老万最近正在学习ES"} { "create": { } } { "content": "老万精通JAVA"} { "create": { } } { "content": "ES从入门到放弃"}
说明:
ElasticSearch 5.0以后,String字段被拆分成两种新的数据类型: text用于全文搜索,会分词,而keyword用于关键词搜索,不进行分词。
补充:官网对wildcard字段类型的说明
说明:
1、采用wildcard通配符查询的字段推荐采用字段type设置为wildcard。
2、text字段会进行分词,wildcard通配符查询检索的是分词后的数据。
3、keyword字段虽然不会进行分词,但执行通配符wildcard查询(特别是带有前导通配符的模式)很慢。
实现方案:
1、sql实现
POST /_sql?format=txt { "query": "SELECT content FROM content_index Where content like '%ES%'" }
查询结果:
转为DSL查看底层实现:
POST /_sql/translate { "query": "SELECT content FROM content_index Where content like '%ES%'" }
执行结果:
底层就是基于wildcard的通配符查询,其中?和*分别代替一个和多个字符。
{ "size" : 1000, "query" : { "wildcard" : { "content" : { "wildcard" : "*ES*", "boost" : 1.0 } } }, "_source" : false, "stored_fields" : "_none_", "docvalue_fields" : [ { "field" : "content" } ], "sort" : [ { "_doc" : { "order" : "asc" } } ] }
2、dsl实现
利用wildcard通配符查询实现,其中?和*分别代替一个和多个字符。
GET content_index/_search { "query": { "wildcard": { "content": { "value": "*ES*" } } } }
查询结果:
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "content_index", "_type" : "_doc", "_id" : "E3E0BnsBxW9JEct2L-d4", "_score" : 1.0, "_source" : { "content" : "老万最近正在学习ES" } }, { "_index" : "content_index", "_type" : "_doc", "_id" : "FXE0BnsBxW9JEct2L-d4", "_score" : 1.0, "_source" : { "content" : "ES从入门到放弃" } } ] } }
总结
本文主要介绍了ES中通过wildcard通配符查询实现like模糊查询。
而sql查询的方式显然适合大众口味。
使用wildcard通配符查询的目标字段的type类型需要设置为wildcard。