目录
(1)空查询:也就是查询所有索引所有文档 等同于match_all
(2)单个属性查询:例如查询字段tweet中包含elasticsearch的文档
一、分页查询
主要使用两个字段
size:表示每页返回多少条结果
from:表示跳过多少条数据
示例:
GET /_search?size=5 (第一页)
GET /_search?size=5&from=5 (第二页)
GET /_search?size=5&from=10 (第三页)
二、常用基本查询
(1)空查询:也就是查询所有索引所有文档 等同于match_all
GET /_search
{
"query": {
"match_all": {}
}
}
(2)单个属性查询:例如查询字段tweet中包含elasticsearch的文档
如果你在一个全文字段上使用 match
查询,在执行查询前,它将用正确的分析器去分析查询字符串:
GET /_search
{
"query": {
"match": {
"tweet": "elasticsearch"
}
}
}
如果在一个精确值的字段上使用它,例如数字、日期、布尔或者一个 not_analyzed
字符串字段,那么它将会精确匹配给定的值
{ "match": { "age": 26 }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text" }}
(3)multi_match查询
multi_match
查询可以在多个字段上执行相同的 match
查询:
{
"multi_match": {
"query": "full text search",
"fields": [ "title", "body" ]
}
}
(4)range查询
range
查询找出那些落在指定区间内的数字或者时间:
{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
(5)term 查询
term
查询被用于精确值匹配,这些精确值可能是数字、时间、布尔或者那些 not_analyzed
的字符串:
{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}
{ "term": { "public": true }}
{ "term": { "tag": "full_text" }}
(6)terms 查询
terms
查询和 term
查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定值中的任何一个值,那么这个文档满足条件:
{ "terms": { "tag": [ "search", "full_text", "nosql" ] }}
(7)exists 查询和 missing 查询
exists
查询和 missing
查询被用于查找那些指定字段中有值 (exists
) 或无值 (missing
) 的文档。这与SQL中的 IS_NULL
(missing
) 和 NOT IS_NULL
(exists
) 在本质上具有共性:
{
"exists": {
"field": "title"
}
}
三、组合多查询
(1)bool查询
如果没有 must
语句,那么至少需要能够匹配其中的一条 should
语句。但,如果存在至少一条 must
语句,则对 should
语句的匹配没有要求。
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }},
{ "range": { "date": { "gte": "2014-01-01" }}}
]
}
}
如果我们不想因为文档的时间而影响得分,可以用 filter
语句来重写前面的例子:
增加带过滤器(filtering)的查询
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }}
],
"filter": {
"range": { "date": { "gte": "2014-01-01" }}
}
}
}
通过将 range 查询移到 filter
语句中,我们将它转成不评分的查询,将不再影响文档的相关性排名。由于它现在是一个不评分的查询,可以使用各种对 filter 查询有效的优化手段来提升性能。
所有查询都可以借鉴这种方式。将查询移到 bool
查询的 filter
语句中,这样它就自动的转成一个不评分的 filter 了。
如果你需要通过多个不同的标准来过滤你的文档,bool
查询本身也可以被用做不评分的查询。简单地将它放置到 filter
语句中并在内部构建布尔逻辑:
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }}
],
"filter": {
"bool": {
"must": [
{ "range": { "date": { "gte": "2014-01-01" }}},
{ "range": { "price": { "lte": 29.99 }}}
],
"must_not": [
{ "term": { "category": "ebooks" }}
]
}
}
}
}
通过混合布尔查询,我们可以在我们的查询请求中灵活地编写 scoring 和 filtering 查询逻辑。
(2)constant_score 查询
尽管没有 bool
查询使用这么频繁,constant_score
查询也是你工具箱里有用的查询工具。它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。
可以使用它来取代只有 filter 语句的 bool
查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助。
{
"constant_score": {
"filter": {
"term": { "category": "ebooks" }
}
}
}
term
查询被放置在 constant_score
中,转成不评分的 filter。这种方式可以用来取代只有 filter 语句的 bool
查询
四、验证查询合法性
查询可以变得非常的复杂,尤其和不同的分析器与不同的字段映射结合时,理解起来就有点困难了。不过 validate-query
API 可以用来验证查询是否合法。
GET /gb/tweet/_validate/query
{
"query": {
"tweet" : {
"match" : "really powerful"
}
}
}
以上 validate
请求的应答告诉我们这个查询是不合法的:
{
"valid" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
}
}
理解错误信息
为了找出 查询不合法的原因,可以将 explain
参数 加到查询字符串中:
GET /gb/tweet/_validate/query?explain
{
"query": {
"tweet" : {
"match" : "really powerful"
}
}
}
explain
参数可以提供更多关于查询不合法的信息。
很明显,我们将查询类型(match
)与字段名称 (tweet
)搞混了:
{
"valid" : false,
"_shards" : { ... },
"explanations" : [ {
"index" : "gb",
"valid" : false,
"error" : "org.elasticsearch.index.query.QueryParsingException:
[gb] No query registered for [tweet]"
} ]
}
理解查询语句
对于合法查询,使用 explain
参数将返回可读的描述,这对准确理解 Elasticsearch 是如何解析你的 query 是非常有用的:
GET /_validate/query?explain
{
"query": {
"match" : {
"tweet" : "really powerful"
}
}
}
我们查询的每一个 index 都会返回对应的 explanation
,因为每一个 index 都有自己的映射和分析器:
{
"valid" : true,
"_shards" : { ... },
"explanations" : [ {
"index" : "us",
"valid" : true,
"explanation" : "tweet:really tweet:powerful"
}, {
"index" : "gb",
"valid" : true,
"explanation" : "tweet:realli tweet:power"
} ]
}
从 explanation
中可以看出,匹配 really powerful
的 match
查询被重写为两个针对 tweet
字段的 single-term 查询,一个single-term查询对应查询字符串分出来的一个term。
当然,对于索引 us
,这两个 term 分别是 really
和 powerful
,而对于索引 gb
,term 则分别是 realli
和 power
。之所以出现这个情况,是由于我们将索引 gb
中 tweet
字段的分析器修改为 english
分析器
五、排序
(1)按照字段的值排序
在这个案例中,通过时间来对 tweets 进行排序是有意义的,最新的 tweets 排在最前。 我们可以使用 sort
参数进行实现:
GET /_search
{
"query" : {
"bool" : {
"filter" : { "term" : { "user_id" : 1 }}
}
},
"sort": { "date": { "order": "desc" }}
}
你会注意到结果中的两个不同点:
"hits" : {
"total" : 6,
"max_score" : null,
"hits" : [ {
"_index" : "us",
"_type" : "tweet",
"_id" : "14",
"_score" : null,
"_source" : {
"date": "2014-09-24",
...
},
"sort" : [ 1411516800000 ]
},
...
}
_score
不被计算, 因为它并没有用于排序。
date
字段的值表示为自 epoch (January 1, 1970 00:00:00 UTC)以来的毫秒数,通过 sort
字段的值进行返回。
首先我们在每个结果中有一个新的名为 sort
的元素,它包含了我们用于排序的值。 在这个案例中,我们按照 date
进行排序,在内部被索引为 自 epoch 以来的毫秒数 。 long 类型数 1411516800000
等价于日期字符串 2014-09-24 00:00:00 UTC
。
其次 _score
和 max_score
字段都是 null
。计算 _score
的花销巨大,通常仅用于排序; 我们并不根据相关性排序,所以记录 _score
是没有意义的。如果无论如何你都要计算 _score
, 你可以将 track_scores
参数设置为 true
。
一个简便方法是, 你可以指定一个字段用来排序:
"sort": "number_of_children"
字段将会默认升序排序,而按照 _score
的值进行降序排序。
(2)多级排序
假定我们想要结合使用 date
和 _score
进行查询,并且匹配的结果首先按照日期排序,然后按照相关性排序:
GET /_search
{
"query" : {
"bool" : {
"must": { "match": { "tweet": "manage text search" }},
"filter" : { "term" : { "user_id" : 2 }}
}
},
"sort": [
{ "date": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
}
排序条件的顺序是很重要的。结果首先按第一个条件排序,仅当结果集的第一个 sort
值完全相同时才会按照第二个条件进行排序,以此类推。
多级排序并不一定包含 _score
。你可以根据一些不同的字段进行排序,如地理距离或是脚本计算的特定值
(3)多值字段的排序
一种情形是字段有多个值的排序, 需要记住这些值并没有固有的顺序;一个多值的字段仅仅是多个值的包装,这时应该选择哪个进行排序呢?
对于数字或日期,你可以将多值字段减为单值,这可以通过使用 min
、 max
、 avg
或是 sum
排序模式 。 例如你可以按照每个 date
字段中的最早日期进行排序,通过以下方法:
"sort": {
"dates": {
"order": "asc",
"mode": "min"
}
}