目录
前言
本篇文章接Elasticsearch搜索数据DSL语法(一)继续介绍查询和过滤器语法,部分内容总结摘抄自《Elasticsearch实战》,仅作笔记。
3、match_phrase查询
既然es6把match的词组功能去除了,那肯定是给了另一个更优的语法,就是match_phrase。match_phrase是专门用来做词组查询的,使用match_phrase来查询index索引中personalIntro字段中包含词组“I handsome”且允许存在的最大分词个数为5的数据,语句如下:
GET /index/_search
{
"query": {
"match_phrase": {
"personalIntro": {
"query": "I handsome",
"slop": 5
}
}
}
}
查询结果如下,需要注意的是slop指的是词组中的分词之间允许分词存在的最大数量,因此在此例中slop的值为5,依然可以查询预期结果。
4、match_phrase_prefix查询
match_phrase_prefix是match_phrase的增强版,它先查找除最后一个分词之前的词组,然后再根据最后一个分词为前缀模糊搜索。例如想要查询personalIntro字段包含词组“I beautiful”以及“na”为前缀的分词的查询语句如下:
GET /index/_search
{
"query": {
"match_phrase_prefix": {
"personalIntro": {
"query": "I beautiful na",
"max_expansions": 0,
"slop":10
}
}
}
}
其中max_expansions在书上以及网上很多地方都说指的是返回的最大匹配项数,但笔者实际操作并不是如此,例如上面max_expansions的值为0,仍然可以返回数据,如下图。此处有大佬知道该字段表达的意思欢迎留言。
5、multi_match查询
以上介绍的查询都是针对单个字段的查询,multi_match可以让我们查询多个字段,即在多个字段上执行同样的查询。例如查询name或personalIntro字段都包含“krystal”的数据,语句如下:
GET /index/_search
{
"query": {
"multi_match": {
"query": "krystal",
"fields": ["name","personalIntro"]
}
}
}
查询结果如下,符合预期。
6、term查询
term查询与match类似,区别是term搜索的词条是没有经过分析的,因此只有精确匹配时才会返回数据。term可以用来查询数字、日期、布尔和文本类型的数据。例如查询age字段的值为8的数据的查询语句如下:
GET /index/_search
{
"query": {
"term": {
"age": 8
}
}
}
查询结果如下,结果符合预期。
然而当我们试图用term来精确查询文本类型的时候发现没有匹配的结果,例如查询name字段的值为“charles hahaha”的数据,发现没有结果返回。这是由于在倒排索引中存储的并不是”charles hahaha“,而是将其分为了两个分词”charles“和”hahaha“。对于某些需要对文本进行精确匹配的场景,我们可以将该文本声明为”keyword“类型使其不被分析。
7、terms查询
terms查询与term查询类似,区别是可以搜索某个字段的多个词条。例如想要搜索age字段的值为8或48的数据的语句如下:
GET /index/_search
{
"query": {
"terms": {
"age":[8,48]
}
}
}
查询结果如下,符合预期。
8、bool查询
在实际的业务场景中,上面介绍的简单的查询语句无法完成较复杂的业务,这时我们需要使用组合查询功能。bool查询允许我们在单独的查询中组合任意数量的查询,指定的查询子句表明哪些部分是必须匹配(must)、应该匹配(should)或者是不能匹配(must_not)的。bool查询中分为以下三种子句:
- must子句:搜索结果必须满足must子句中的全部搜索条件;
- should子句:对于搜索结果,should子句中的条件可以匹配也可以不匹配,但匹配数至少要达到minimum_should_match参数所设置的数量。如果bool查询中有must子句,则minimum_should_match参数默认值为0,否则为1。
- must_not子句:搜索结果不能匹配must_not子句中任何一个条件。
例如查询index索引中name字段包含“charles”且age=18且personalIntro字段不包含handsome的数据的语句如下:
GET /index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "charles"
}
},
{
"term": {
"age": 18
}
}
],
"must_not": [
{
"match": {
"personalIntro":"handsome"
}
}
]
}
}
}
查询结果如下,符合预期。
为了验证should子句,再查询name字段包含“charles”或"wawawawawa",且需要满足以下条件中最少两个条件:①age=8②age=19③personalIntro字段包含词条"I"和以“hand”开头的词条,词组之间的“最大距离”为3,该语句如下:
GET /index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "charles wawawawawa"
}
}
],
"should": [
{
"term": {
"age": 8
}
},
{
"term": {
"age": 18
}
},
{
"match_phrase_prefix": {
"personalIntro": {
"query": "I hand",
"slop":3
}
}
}
],
"minimum_should_match": 2
}
查询结果如下,符合预期。
9、term过滤器
term过滤器与term查询类似,它们之间只是过滤器与查询的区别。在前面提到过在es5.x已经弃用的filtered过滤器语法,5.x以后使用bool查询来替代,同样可以支持filter子句。查询age=18且gender=female的数据的查询语句如下:
GET /index/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"gender": "female"
}
}
],
"filter": {
"term": {
"age": 18
}
}
}
}
}
查询结果如下,符合预期。
10、布尔过滤器
布尔过滤器与布尔查询也是类似的,只是它组合的是过滤器。使用bool过滤器查询index索引中name字段包含“charles”且age=18且personalIntro字段不包含handsome的数据的语句如下:
GET /index/_search
{
"query": {
"bool": {
"filter": {
"bool": {
"must": [
{
"match": {
"name": "charles"
}
},
{
"term": {
"age": 18
}
}
],
"must_not": [
{
"match": {
"personalIntro":"handsome"
}
}
]
}
}
}
}
}
查询结果如下,符合预期。另外,从结果可以看到_score是0.0,也证明了过滤器确实不计算分数。
11、range查询和过滤器
range查询可以让我们查询介于一定范围之内的值,适用于数字、日期甚至是字符串。为了使用范围查询,需要指定某个字段的上界值和下界值,需要使用的参数如下表:
参数 | 含义 |
---|---|
gt | 大于某值,不包括值本身 |
gte | 大于某值,包括值本身 |
lt | 小于某值,不包括值本身 |
lte | 小于某值,包括值本身 |
例如查询index索引中age字段大于等于8且小于28,的数据的查询语句如下:
GET /index/_search
{
"query": {
"range": {
"age": {
"gte": 8,
"lt": 28
}
}
}
}
查询结果如下,符合预期。
仔细观察可以看到虽然我们使用的是range查询,但每个结果的_score都是1.0,也就是说并没有计算分数。这是因为文档是否在范围内是yes or no的问题,这与过滤器的原理是一致的,因此不用也不需要计算分数,此时我们使用range过滤器更好一些。关于range过滤器的语法与前面介绍的过滤器语法类似,此处不再赘述。
12、wildcard查询
wildcard查询可以作为正则表达式的搜索,与其他高级语言的通配符类似,wildcard查询在字符串类型中“*”通配符可以匹配任何数量的字符,而“?”通配符可以匹配单个字符。可以混合使用多个“*”和“?”来匹配较为复杂的通配模版,但字符串被分析后,一般情况下空格会被除去,此时“?”无法匹配空格。例如可以使用“h*so?e”来匹配词条"handsome",但无法使用“a?h*e?boy”来匹配词条“a handsome boy”,因为在倒排索引中“a handsome boy”会被分析成“a”、"handsome"和“boy”。
使用wildcard查询来查询index索引中personalIntro字段匹配“h*so?e”通配模版的数据的查询语句如下:
GET /index/_search
{
"query": {
"wildcard": {
"personalIntro": {
"wildcard": "h*so?e"
}
}
}
}
查询结果如下,符合预期。
需要注意的是,wildcard查询不像match等其他查询那么轻量,查询词条越早出现通配符,es就需要越多的工作来进行匹配,因此在使用该查询时需要注意可能在数据量比较少的开发环境没有问题,到了数据量较大的生产环境就出现性能问题。
总结
需要强调的是,Elasticsearch的版本更替较频繁,学习时一定要注意版本,建议像笔者这样在kibana上多敲一些。