Elasticsearch搜索查询语法
💛原文地址为https://www.cnblogs.com/haixiang/p/12095578.html,转载请注明出处!
🍎es与SpringBoot的整合以及常用CRUD、搜索API已被作者封装,开箱即用效果很好,欢迎star谢谢!github
查询简介#
叶子查询子句
叶子查询子句在特定字段中查找特定值,例如match,term或range查询。 这些查询可以自己使用。
复合查询子句
复合查询子句包装其他叶查询或复合查询,并用于以逻辑方式组合多个查询(例如bool或dis_max查询),或更改其行为(例如constant_score查询)。复合查询子句包含以下几种:
- bool query
- boosting query
- constant_score query
- dis_max query
- function_score query
我们通常只会用到bool查询
查询子句的行为会有所不同,具体取决于它们是在查询上下文中(Query)还是在过滤器(Filter)上下文中使用。
全文检索#
在query context
中,查询子句回答“此文档与该查询子句的匹配程度如何”的问题。除了确定文档是否匹配外,查询子句还计算_score
元字段中的相关性得分。es的搜索结果也默认根据_score
排名返回。
match#
-
match
是标准的全文检索 -
在匹配之前会先对查询关键字进行分词
-
可以指定分词器来覆盖
mapping
中设置的搜索分词器
首先超级羽绒服
关键字先会被分词为超级
、羽绒服
然后再去es中查询与这两个分词相匹配的文档,依据相关度即分值得到以下结果。
GET idx_pro/_search
{
"query": {
"match": {
"name": {
"query": "超级羽绒服",
"analyzer": "ik_smart"
}
}
}
}
冬天超级暖心羽绒服 冬天暖心羽绒服 冬日羽绒服 花花公子羽绒服 花花公子暖心羽绒服
不使用配置的话可以采用如下简写方式
"query": {
"match": {"name": "超级羽绒服"}
}
match_phrase#
- 可以搜索分词相邻的结果,eg 根据
新疆苹果
可以搜到香甜新疆苹果
而搜不到新疆香甜苹果
- 可以使用
slop
指定两个匹配的token
位置距离的最大值。 - 可以使用
analyzer
指定分词器,覆盖mapping
中设置的search_analyzer
如下我们对"花花公子羽绒服"进行分词后发现,返回结果除了每个token
之外,还拥有位置信息start_offset
和end_offset
。位置信息可以被保存在倒排索引(Inverted Index)中,像match_phrase
这样位置感知(Position-aware)的查询能够使用位置信息来匹配那些含有正确单词出现顺序的文档,且在这些单词之间没有插入别的单词。
GET idx_pro/_analyze
{
"text":"花花公子羽绒服",
"analyzer" : "ik_smart"
}
{
"tokens" : [
{
"token" : "花花公子",
"start_offset" : 0,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "羽绒服",
"start_offset" : 4,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 1
}
]
}
如下是我们的样本数据
冬日工装裤 花花公子帅气外套 花花公子外套 冬天暖心羽绒服 冬日羽绒服 花花公子羽绒服 花花公子暖心羽绒服
冬天超级暖心羽绒服
我们查询超级羽绒服
搜索不到数据,因为没有超级羽绒服这样的短语存在。
GET idx_pro/_search
{
"query": {
"match_phrase": {
"name": "超级羽绒服"
}
}
}
搜索暖心羽绒服
即可搜索到如下三个数据,因为暖心羽绒服
被分词为暖
、 心
、 羽绒服
三部分,搜索到的结果必须符合他们三个分词的位置紧挨着。
GET idx_pro/_search
{
"query": {
"match_phrase": {
"name": "暖心羽绒服"
}
}
}
冬天暖心羽绒服 冬天超级暖心羽绒服 花花公子暖心羽绒服
我们在设置了slop
后允许超级
和羽绒服
这两个分词后的token
距离最大值为2,可以搜索到如下数据了。因为冬天超级暖心羽绒服
分词结果为冬天
,超级
,暖
,心
,羽绒服
,超级
与羽绒服
距离正好为2,所以能匹配到。
GET idx_pro/_search
{
"query": {
"match_phrase": {
"name": {
"query": "超级羽绒服",
"analyzer": "ik_smart",
"slop": 2
}
}
}
}
冬天超级暖心羽绒服
Filter#
其实准确来说,ES中的查询操作分为2种:查询(query)和过滤(filter)。查询即是之前提到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序。而过滤(filter)只会筛选出符合的文档,并不计算得分,且它可以缓存文档。所以,单从性能考虑,过滤比查询更快。
换句话说,过滤适合在大范围筛选数据,而查询则适合精确匹配数据。一般应用时,应先使用过滤操作过滤数据,然后使用查询匹配数据。
在Filter context
中,查询子句回答问题“此文档是否与此查询子句匹配?”答案是简单的“是”或“否”,即不计算分数。过滤器上下文主要用于过滤结构化数据,例如:
- 该食品的生产日期是否在2018-2019之间
- 该商品的状态是否为"已上架"
Ps:常用过滤器将由Elasticsearch自动缓存,以提高性能。
bool组合查询#
bool查询可以组合多种叶子查询,包含如下:
- must:出现于匹配查询当中,有助于匹配度(_score)的计算
- filter:必须满足才能出现,属于过滤,不会影响分值的计算,但是会过滤掉不符合的数据
- should:该条件下的内容是应该满足的内容,如果符合会增加分值,不符合降低分值,不会不显示
- must_not:满足的内容不会出现,与
filter
功能相反,属于过滤,不会影响分值的计算,但是会过滤掉不符合的数据
term-level query#
我们可以使用term-level
根据结构化的数据(例如ip、商品的id、价格等分词后无意义的数据)来精准查询文档,
与full-text
全文检索不同,查询的关键字不进行分词,直接去es中匹配文档。
常见的term-level
级别的查询有(其他查询请参考官网):
-
term query
返回文档中精确包含关键字的文档,苏布尔贵族大米
不会分词,直接去es中匹配文档GET idx_item/_search { "query": { "term": {"title": "东北贵族大米"} } }
-
terms query
相当于多个term
查询GET idx_item/_search { "query": { "terms": {"title": ["苏泊尔","小米"]} } }
-
exists query
返回有name
字段的文档,注意,如下情况将搜索不到文档:- 该字段的值为
null
或者是[]
,空字符串是可以搜索到的""
- 该字段在
mapping
中设置了index:false
- 该字段长度超出了
mapping
中的ignore_above
的设置 - The field value was malformed and
ignore_malformed
was defined in the mapping
GET idx_pro/_search { "query": { "exists": { "field": "name" } } }
- 该字段的值为
-
range query
Returns documents that contain terms within a provided range.GET _search { "query": { "range" : { "age" : { "gte" : "2019-12-10", "lte" : "2020-11-11", "format" : "yyyy-MM-dd" } } } }
-
ids query
根据文档的_id
返回文档GET /_search { "query": { "ids" : { "values" : ["1", "4", "100"] } } }
示例#
must_not
和filter
用来过滤,而should
是应该满足的条件,不是必须满足的条件,会影响分值的计算。
GET idx_pro/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "花花公子羽绒服"
}
}
],
"must_not": [
{
"term": {
"proId": 6
}
}
],
"should": [
{
"terms": {
"name.keyword": ["花花公子暖心羽绒服", "花花公子外套"]
}
}
],
"filter": {
"range": {
"createTime": {
"gte": "2019-12-12 17:56:56",
"lte": "2019-12-19 17:56:56",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
}