Elasticsearch 提供了一个完整的基于 JSON 的查询语言(DSL)来定义查询,它由两种类型的子句组成:

  • 叶查询子句:查找特定字段中的特定值,例如 match、term 或 range 查询,这些查询可以自己使用
  • 复合查询子句:包装其他叶查询或复合查询,并以逻辑方式组合多个查询(如 bool 或 dis_max)

下面我们来详细介绍各种查询子句的使用:

全文查询

全文搜索通常用于在 text 字段(例如:一封邮件的正文)上进行全文搜索,在执行全文查询时会将每个文档字段的分词器(或搜索指定的分词器)应用于查询字符串并对其分词,然后每个词项逐个进行底层的查询,最后将结果进行合并并为每个文档计算相关性算分。

1. match

match 查询会对 text 类型的字段进行分词,然后再进行搜索。默认分词后查询语句中的任何一个词项被匹配文档就会被搜索到。如果想查询匹配所有关键字的文档,可以用 and 操作符连接。

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "match" : {
  5. "message" : {
  6. "query" : "this is a test",
  7. "operator" : "and"
  8. }
  9. }
  10. }
  11. }'

如果采用 match 查询对一个 keyword 类型的字段进行搜索,Elasticsearch 会自动转成 term query。

2. match_phrase

match_phrase 查询首先会把 query 内容分词,同时文档还要满足以下两个条件才会被搜索到:

  • 分词后所有词项都要出现在该字段中
  • 字段中的词项顺序要一致

例如,有以下 3 个文档,使用 match_phrase 查询 “hello world” 只有前两个文档会被匹配:

  1. curl -X POST "localhost:9200/twitter/_doc?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "message":"I said hello world"
  4. }'
  5. curl -X POST "localhost:9200/twitter/_doc?pretty" -H 'Content-Type: application/json' -d'
  6. {
  7. "message":"Hello World"
  8. }'
  9. curl -X POST "localhost:9200/twitter/_doc?pretty" -H 'Content-Type: application/json' -d'
  10. {
  11. "message":"world hello"
  12. }'
  13. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  14. {
  15. "query": {
  16. "match_phrase" : {
  17. "message" : "hello world"
  18. }
  19. }
  20. }'

此外,还可以通过 slop 参数指定在词项之间允许有多少个其他词项:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "match_phrase" : {
  5. "message" : {
  6. "query" : "hello world",
  7. "slop" : 1
  8. }
  9. }
  10. }
  11. }'

3. match_phrase_prefix

match_phrase_prefix 和 match_phrase 类似,只不过 match_phrase_prefix 把最后一个 term 视为前缀,用于匹配以该 term 开头的任何单词。

如下搜索匹配 quick brown fox 或 two quick brown ferrets 但不匹配 the fox is quick and brown

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "match_phrase_prefix" : {
  5. "message" : "quick brown f"
  6. }
  7. }
  8. }'

4. multi_match

multi_search 是 match 的升级,用于单字符串多字段搜索,并且支持对要搜索的字段名称使用通配符。默认计算相关性算分的方式为 best_fields,同 dis_max 一样取的是最匹配的文档。

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "multi_match" : {
  5. "query": "Will Smith",
  6. "fields": [ "title", "*_name" ]
  7. }
  8. }
  9. }'

当我们跨字段执行搜索时,默认情况下,如果想让每个字段都匹配 query 中的句子而非单词的话,是不支持通过 operator 参数指定 and 的方式的,此时你可以使用 copy_to 去解决,但需要额外的存储空间。

你也可以修改 multi_search 的搜索类型为 cross_fields 以支持 operator 参数:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "multi_match" : {
  5. "query" : "Will Smith",
  6. "type" : "cross_fields",
  7. "operator" : "and",
  8. "fields": [ "title", "*_name" ]
  9. }
  10. }
  11. }'

5. common

common 词项查询是一种在不牺牲性能的情况下替代停用词提高搜索准确率和召回率的方案。

查询中的每个词项都有一定的代价,以搜索 “The brown fox” 为例,query 会被解析成三个词项 “the” “brown” 和 “fox”,每个词项都会到索引中执行一次查询。很显然包含 “the” 的文档非常多,相比其他词项,”the” 的重要性会低很多。传统的解决方案是把 “the” 当作停用词处理,去除停用词之后可以减少索引大小,同时在搜索时减少对停用词的搜索。

虽然停用词对文档评分影响不大,但当停用词有重要意义时,去除停用词就不是完美的解决方案了。如果去除停用词就无法区分 “happy” 和 “not happy”,搜索的准确率和召回率就会降低。

common_terms query 提供了一种解决方案,它把 query 分词后的词项分成重要词项(低频词项)和不重要的词项(高频词,也就是之前的停用词)。在搜索时首先搜索和重要词项匹配的文档,这些文档是词项出现较少并且词项对其评分影响较大的文档。然后执行第二次查询,搜索对评分影响较小的高频词项,但是不计算所有文档的评分,而是只计算第一次查询已经匹配的文档得分。如果一个查询中只包含高频词,那么会通过 and 连接符执行一个单独的查询,即搜索所有的词项。

词项是高频词还是低频词是通过 cutoff_frequency 来设置阀值的,取值可以是绝对频率(频率大于 1)或相对频率(0~1)。例如,文档频率高于 0.1% 的词项将会被当作高频词项,词频之间可以用 low_freq_operatorhigh_freq_operator 参数连接。设置低频词操作符为 “and” 使所有的低频词都是必须搜索的,示例如下:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "common": {
  5. "body": {
  6. "query": "nelly the elephant as a cartoon",
  7. "cutoff_frequency": 0.001,
  8. "low_freq_operator": "and"
  9. }
  10. }
  11. }
  12. }'

上述操作等价于:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "bool": {
  5. "must": [
  6. { "term": { "body": "nelly"}},
  7. { "term": { "body": "elephant"}},
  8. { "term": { "body": "cartoon"}}
  9. ],
  10. "should": [
  11. { "term": { "body": "the"}},
  12. { "term": { "body": "as"}},
  13. { "term": { "body": "a"}}
  14. ]
  15. }
  16. }
  17. }'

6. query_string

query_string 查询是与 Lucene 查询语句的语法结合非常紧密的一种查询,允许在一个查询语句中使用多个特殊条件关键字(如:AND、OR、NOT)对多个字段进行查询,建议熟悉 Lucene 查询语法的用户去使用。

例子如下:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "query_string" : {
  5. "fields" : ["content", "name"],
  6. "query" : "this AND that"
  7. }
  8. }
  9. }'

上述查询等价于:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "(content:this OR name:this) AND (content:that OR name:that)"
  6. }
  7. }
  8. }'

7. simple_query_string

simple_query_string 类似 query_string,是一种适合直接暴露给用户,并且具有非常完善的查询语法的查询语句,解析过程中发生错误不会抛出异常,会忽略错误的语法。不支持 AND、OR、NOT 操作符,会当作字符串处理,提供了 + 来代替 AND、- 代替 NOT、| 代替 OR

例子如下:

  1. curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "simple_query_string" : {
  5. "query": "\"fried eggs\" +(eggplant | potato) -frittata",
  6. "fields": ["title^5", "body"],
  7. "default_operator": "and"
  8. }
  9. }
  10. }'

词项查询

Term 是表达语义的最小单位,我们可以使用 Term 级别的查询根据结构化数据中的精确值查找文档,与全文查询不同,使用词项查询不会对搜索词进行分析,会将输入做为一个整体,在倒排索引中查找准确的词项并使用相关性算分公式为每个包含该词项的文档进行相关性算分。

1. term

term 查询用来查找指定字段中包含给定单词的文档,term 查询不会对查询词进行分词,只有查询词和文档中的词精确匹配才会被搜索到,即使字段为 text 类型,应用场景为查询人名、地名等需要精准匹配的需求。

注意:term 查询是包含,不是完全相等,针对多值字段查询要尤其注意。如果要对多值字段进行精确匹配,可以增加一个 count 字段来统计值的词项个数,在搜索时通过 bool query 进行词项和词项个数的精确匹配。

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "term": {
  5. "user": "kimchy"
  6. }
  7. }
  8. }'

2. terms

terms 查询是 term 查询的升级,可以用来查询文档中包含多个词的文档。如下示例查询 user 字段中包含了关键词 kimchy 或 elasticsearch 的文档:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query" : {
  4. "terms" : {
  5. "user" : ["kimchy", "elasticsearch"],
  6. "boost" : 1.0
  7. }
  8. }
  9. }'

3. terms_set

terms_set 查询与 terms 查询类似,但是可以定义返回文档所需的匹配术语的数量,即返回只匹配 terms 列表中的两个或三个的文档。因此在大多数情况下,需要在索引定义中包含一个数字字段映射用来使用 terms_set 查询,这个数字字段包含返回文档所需的匹配条件的数量。

示例如下,我们先创建一个包含数字字段 required_matches 的索引定义:

  1. curl -X PUT "localhost:9200/job-candidates?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "mappings": {
  4. "properties": {
  5. "name": {
  6. "type": "keyword"
  7. },
  8. "programming_languages": {
  9. "type": "keyword"
  10. },
  11. "required_matches": {
  12. "type": "long"
  13. }
  14. }
  15. }
  16. }'

写入文档:

  1. curl -X PUT "localhost:9200/job-candidates/_doc/1?refresh&pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "name": "Jane Smith",
  4. "programming_languages": ["c++", "java"],
  5. "required_matches": 2
  6. }'

如下查询表示最少匹配 terms 列表中的两项,因为最小匹配单词数量为 required_matches 字段:

  1. curl -X GET "localhost:9200/job-candidates/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "terms_set": {
  5. "programming_languages": {
  6. "terms": ["c++", "java", "php"],
  7. "minimum_should_match_field": "required_matches"
  8. }
  9. }
  10. }
  11. }'

4. range

range 查询用于匹配在某一范围内的数值型、日期类型或字符串型字段的文档,比如搜索哪些书籍的价格在 50 到 100 之间、哪些书籍的出版时间在 2014 年到 2016 年之间。使用 range 查询只能查询一个字段,不能作用在多个字段上。range 查询支持的参数有以下几种:

  • gt:大于
  • gte:大于等于
  • lt:小于
  • lte:小于等于

如下示例返回 age 字段在 10 到 20 之间的文档:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "range" : {
  5. "age" : {
  6. "gte" : 10,
  7. "lte" : 20
  8. }
  9. }
  10. }
  11. }'

如下示例返回 post_date 字段在 2020-01-01 到 2020-12-30 之间的文档:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "range" : {
  5. "post_date" : {
  6. "gte" : "2020-01-01",
  7. "lte" : "2020-12-30",
  8. "format" : "yyyy-MM-dd"
  9. }
  10. }
  11. }
  12. }'

5. exists

exists 查询会返回字段中至少有一个非空值的文档,举例说明:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "exists": {
  5. "field": "user"
  6. }
  7. }
  8. }'

以下文档会匹配上面的查询:

  • {“user”:”jane”} 有 user 字段,且不为空
  • {“user”:””} 有 user 字段,值为空字符串
  • {“user”:[“jane”] } 有 user 字段,值不为空
  • {“user”:[“jane”,null] 有 user 字段,至少一个值不为空即可

下面的文档都不会被匹配:

  • {“user”: null } 虽然有 user 字段,但值为空
  • {“user”:[]} 虽然有 user 字段,但值为空
  • {“user”: [null] } 虽然有 user 字段,但值为空
  • {“name”: “kimmiy”} 没有 user 字段

    6. prefix

    prefix 查询用于查询某个字段中以给定前缀开始的文档,比如查询 title 中含有以 java 为前缀的关键词的文档,那么含有 java、javascript、javaee 等所有以 java 开头关键词的文档都会被匹配。示例如下:
    1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
    2. {
    3. "query": {
    4. "prefix": {
    5. "title": "java"
    6. }
    7. }
    8. }'

    7. wildcard

    wildcard 查询中文译为通配符查询,支持单字符通配符和多字符通配符,其中:? 用来匹配一个任意字符,* 用来匹配零个或多个字符。以 H?tland 为例,Hatland、Hbtland 等都可以匹配,但是不能匹配 Htland。和 prefix 查询一样,wildcard 查询的查询性能也不是很高,需要消耗较多的 CPU 资源。

下面举一个 wildcard 查询的例子,假设需要找某一作者写的书,但是忘记了作者名字的全称,只记住了前两个字,那么就可以使用通配符查询,查询语句如下:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "wildcard": {
  5. "author": "kil*"
  6. }
  7. }
  8. }'

8. regexp

Elasticsearch 也支持正则表达式查询,通过 regexp 查询可以查询指定字段包含与指定正则表达式匹配的文档。
例如需要匹配以 W 开头紧跟着数字的邮政编码,可使用正则表达式构造如下查询语句:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "regexp": {
  5. "postcode": "W[0-9].+"
  6. }
  7. }
  8. }'

9. fuzzy

编辑距离又称 Levenshtein 距离,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数,编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符,调换两个相邻的字符。fuzzy 查询就是通过计算词项与文档的编辑距离来得到结果的,但是使用 fuzzy 查询需要消耗的资源比较大,查询效率不高,适用于需要模糊查询的场景。

举例如下,用户在输入查询关键词时不小心把 “javascript” 拼成 “javascritp”,在存在拼写错误的情况下使用模糊查询仍然可以搜索到含有 “javascript” 的文档,查询语句如下:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "fuzzy": {
  5. "title": ""javascritp""
  6. }
  7. }
  8. }'

10. ids

ids 查询用于查询具有指定 id 的文档,也可以接受一个数组。如下示例:

  1. curl -X GET "localhost:9200/twitter/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "ids" : {
  5. "values" : ["1", "4", "100"]
  6. }
  7. }
  8. }'

复合查询

复合查询就是把一些简单查询组合在一起实现更复杂的查询需求,以组合它们的结果和分数。除此之外复合查询还可以控制另外一个查询的行为,将其从查询切换到过滤。

1. constant_score

constant_score 查询可以包装一个过滤查询,并返回匹配过滤器中的查询条件且相关性评分都等于 boost 参数值的文档,实际上,它将 query 转成了 filter,避免了相关性算分的计算开销并能有效利用缓存。

下面的查询语句会返回 user 字段中含有关键词 “kimchy” 的所有文档,且返回的文档的相关性评分都为 1.2 这个常量:

  1. curl -X GET "localhost:9200/twittwr/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "constant_score" : {
  5. "filter" : {
  6. "term" : { "user" : "kimchy"}
  7. },
  8. "boost" : 1.2
  9. }
  10. }
  11. }'

返回结果如下,所有 user 字段为 kimchy 的文档的评分都变成了我们设置的常量 1.2 了:

  1. {
  2. "took" : 5,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 13,
  6. "successful" : 13,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 2,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 1.2,
  16. "hits" : [
  17. {
  18. "_index" : "twitter",
  19. "_type" : "_doc",
  20. "_id" : "pOwcJXoBg2C-dN53ZQUN",
  21. "_score" : 1.2,
  22. "_source" : {
  23. "user" : "kimchy",
  24. "post_date" : "2009-11-15T14:12:12",
  25. "message" : "trying out Elasticsearch"
  26. }
  27. },
  28. {
  29. "_index" : "twitter",
  30. "_type" : "_doc",
  31. "_id" : "1",
  32. "_score" : 1.2,
  33. "_source" : {
  34. "user" : "kimchy",
  35. "post_date" : "2009-11-15T14:12:12",
  36. "message" : "trying out Elasticsearch"
  37. }
  38. }
  39. ]
  40. }
  41. }

2. bool

bool 查询可以把任意多个简单查询组合在一起,常用于多条件多字段查询,可以使用 mustshouldmust_notfilter 选项来表示简单查询间的逻辑,每个 must 和 should 选项的得分将被加在一起,以提供每个文档的最终得分。而 must_not 和 filter 选项则在筛选上下文中执行。每个选项都可以出现 0 次到多次,它们的含义如下:

  • must:文档必须匹配 must 选项下的查询条件,相当于逻辑运算的 AND,并将对分数产生影响

  • should:文档可以匹配 should 选项下的查询条件也可以不匹配,相当于逻辑运算的 OR。通常与minimum_should_match 配合使用来指定应该匹配的数量

  • must_not:匹配该选项下的查询条件的文档不会被返回

  • filter:和 must 一样,匹配 filter 选项下的查询条件的文档才会被返回,但 filter 不评分只过滤

假设要查询 user 中包含关键词 kimchy 且 tag 为 tech 且 age 在 10 到 20 之间,message 可以包含也可以不包含 wow 或 elasticsearch 的文档,构造的 bool 查询语句如下:

  1. curl -X POST "localhost:9200/twittwr/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "bool" : {
  5. "must" : {
  6. "term" : { "user" : "kimchy" }
  7. },
  8. "filter": {
  9. "term" : { "tag" : "tech" }
  10. },
  11. "must_not" : {
  12. "range" : {
  13. "age" : { "gte" : 10, "lte" : 20 }
  14. }
  15. },
  16. "should" : [
  17. { "term" : { "tag" : "wow" } },
  18. { "term" : { "tag" : "elasticsearch" } }
  19. ],
  20. "minimum_should_match" : 1
  21. }
  22. }
  23. }'

此外,bool 查询也支持嵌套 bool 查询,可通过 boost 参数影响文档最终的相关性算分。

3. dis_max

dis_max 查询与 bool 查询有一定联系也有一定区别,dis_max 查询支持多并发查询,可返回与一个或多个查询条件子句匹配的文档。与 bool 查询的 should 可以将所有匹配查询的分数相结合的方式不同,dis_max 查询只使用最佳匹配查询条件的分数。示例如下:

  1. curl -X GET "localhost:9200/twittwr/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "dis_max" : {
  5. "queries" : [
  6. { "term" : { "title" : "Quick pets" }},
  7. { "term" : { "body" : "Quick pets" }}
  8. ]
  9. }
  10. }
  11. }'

在 queries 中包含一个或多个查询子句。返回的文档必须匹配一个或多个查询子句。如果一个文档匹配多个查询的话,Elasticsearch 会使用最佳匹配查询条件的相关性得分。

4. function_score

function_score 可以在查询结束后,对每一个匹配的文档进行一系列的重新算分,根据新生成的分数排序。这个查询在有些情况下非常有用,比如通过评分函数计算文档得分的代价比较高,此时可以改用过滤器加自定义评分函数的方式来取代传统的评分方式。

使用 function_score 查询时,用户需定义一个查询和一至多个评分函数,评分函数会对查询到的每个文档分别计算得分,Elasticsearch 提供了几种默认的评分函数:

  • weight:为每一个文档设置一个简单而不被规范化的权重
  • field_value_factor:通过 field 指定某个字段的值作为因数,新算分=老算分*字段值
  • random_score:为每一个文档使用一个随机算分
  • 衰减函数:以某个字段的值为标准,距离某个值越近得分越高
  • script_score:自定义脚本完全控制算分逻辑

下面这条查询语句会返回 twittwr 索引中的所有文档,文档的最大得分为 5 且每个文档的得分是随机生成的,权重的计算模式为相乘模式:

  1. curl -X GET "localhost:9200/twittwr/_search?pretty" -H 'Content-Type: application/json' -d'
  2. {
  3. "query": {
  4. "function_score": {
  5. "query": { "match_all": {} },
  6. "boost": "5",
  7. "random_score": {},
  8. "boost_mode":"multiply"
  9. }
  10. }
  11. }'

还可以使用脚本自定义评分公式,这里把 price 值的十分之一开方作为每个文档的得分,查询语句如下:

curl -X GET "localhost:9200/twittwr/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "function_score": {
            "query": {
                "match": { "user": "kimchy" }
            },
            "script_score" : {
                "script" : {
                  "source": "Math.sqrt(doc[\'price\'].value/10)"
                }
            }
        }
    }
}'

5. boosting

boosting 查询用于需要对两个查询的评分进行调整的场景,boosting 查询会把两个查询封装在一起并降低其中 一个查询的评分。boosting 查询包括 positivenegativenegative_boost 三个部分:

  • positive 中的查询评分保持不变
  • negative 中的查询会降低文档评分
  • negative_boost 指明 negative 中降低的权值

如果我们想对 2015 年之前出版的书降低其相关性评分,则可以构造一个 boosting 查询:

curl -X GET "localhost:9200/books/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "boosting" : {
            "positive" : {
                "term" : {
                    "title" : "java"
                }
            },
            "negative" : {
                 "range" : {
                     "publish_time" : {
                         "lte" : "2015-01-01"
                     }
                }
            },
            "negative_boost" : 0.5
        }
    }
}'

上面的查询中指定了抑制因子为 0.5,即 publish_time 的值在 2015-01-01 之后的文档的相关性得分不变,但在之前的文档的相关性得分变为原得分的 0.5 倍。

嵌套查询

文档中可能包含 nested 类型的字段,这些字段用来索引一些数组对象,每个对象都可以作为一条独立的文档被查询出来。nested 查询可以包装另一个查询以搜索嵌套字段,就好像它们被索引为单独的文档一样。

使用示例如下,info 的字段类型为 nested:

curl -X GET "localhost:9200/my_index/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query":  {
        "nested" : {
            "path" : "info",
            "query" : {
                "bool" : {
                    "must" : [
                    { "match" : {"info.name" : "blue"} },
                    { "range" : {"info.count" : {"gt" : 5}} }
                    ]
                }
            }
        }
    }
}'
  • path:要搜索的嵌套对象的路径(必填)
  • query:希望在 path 指定的嵌套对象上运行的查询

如果是执行多级嵌套查询,示例如下,其中 driver 是 nested 类型,driver 中的 vehicle 也是 nested 类型:

curl -X GET "localhost:9200/drivers/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query" : {
        "nested" : {
            "path" : "driver",
            "query" : {
                "nested" : {
                    "path" :  "driver.vehicle",
                    "query" :  {
                        "bool" : {
                            "must" : [
                                { "match" : { "driver.vehicle.make" : "Powell Motors" } },
                                { "match" : { "driver.vehicle.model" : "Canyonero" } }
                            ]
                        }
                    }
                }
            }
        }
    }
}'

地理位置查询

Elasticsearch 可以对地理位置点 geo_point 类型和地理位置形状 geo_shape 类型的数据进行搜索。

1. geo_distance

geo_distance 查询可以查找在一个中心点指定范围内的地理点文档。例如查找距离天津 200km 以内的城市,其中 location 的字段类型为 geo_point:

curl -X GET "localhost:9200/my_locations/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_distance" : {
                    "distance" : "200km",
                    "location" : {
                        "lat" : 39.0851000000,
                        "lon" : 117.1993700000
                    }
                }
            }
        }
    }
}'

按各城市离北京的距离排序:

curl -X GET "localhost:9200/my_locations/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "match_all":{}
        "sort" : [
          {
            "geo_distance" : {
                "unit" : "km",
                "location" : "39.0851000000,117.1993700000"
            }
          }
        ]
    }
}'

2. geo_bounding_box

geo_bounding_box 查询用于查找落入指定的矩形内的地理坐标,查询由两个点确定一个矩形:

curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_bounding_box" : {
                    "location" : {
                        "top_left" : {
                            "lat" : 40.73,
                            "lon" : -74.1
                        },
                        "bottom_right" : {
                            "lat" : 40.01,
                            "lon" : -71.12
                        }
                    }
                }
            }
        }
    }
}'

3. geo_polygon

geo_polygon 查询用于查找在指定多边形内的地理点,多边形由查询时提供的点组成:

curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool" : {
            "must" : {
                "match_all" : {}
            },
            "filter" : {
                "geo_polygon" : {
                    "location" : {
                        "points" : [
                            {"lat" : 40, "lon" : -70},
                            {"lat" : 30, "lon" : -80},
                            {"lat" : 20, "lon" : -90}
                        ]
                    }
                }
            }
        }
    }
}'

4. geo_shape

geo_shape 查询用于查询 geo_shape 字段类型的地理数据。关于经纬度的顺序这里做一个说明,geo_shape 类型中的点是经度在前纬度在后,这一点需要特别注意。地理形状之间的关系有相交、包含、不相交三种。如下示例,其中 location 为 geo_shape 字段类型:

curl -X GET "localhost:9200/example/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "query":{
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_shape": {
                    "location": {
                        "shape": {
                            "type": "envelope",
                            "coordinates" : [[13.0, 53.0], [14.0, 52.0]]
                        },
                        "relation": "within"
                    }
                }
            }
        }
    }
}'