版本5.0 官方文档英文版
相关文章:
五、浏览你的数据
现在我们已经概览了基础,让我们看下更实用的数据集。这里已经准备好了一批虚构的用户银行账户JSON文档,每一个文档都是如下结构:
{
"account_number": 0,
"balance": 16623,
"firstname": "Bradshaw",
"lastname": "Mckenzie",
"age": 29,
"gender": "F",
"address": "244 Columbus Place",
"employer": "Euron",
"email": "bradshawmckenzie@euron.com",
"city": "Hobucken",
"state": "CO"
}
同时会创建一个bank索引。
5.1 搜索API
现在让我们一起开始一些简单的搜索。有两个基本的方式来执行搜索:
- 通过
REST request URI
发送参数 - 通过
REST request body
发送参数
request body方法可以让你通过灵活、更直观的JSON格式来搜索。我们将会尝试一个REST request URI方法搜索的例子但是在这份文档的剩余部分只会使用request body method这种方式。
搜索API从_search
开始,下面的例子会返回bank索引里所有文档:
GET /bank/_search?q=*&sort=account_number:asc&pretty
让我们仔细分析这个搜索请求。我们从bank索引里搜索,q=*
参数指示Elasticsearch去匹配索引中所有的文档。sort=account_number:asc
参数表示使用文档中account_number
字段按照ascii码顺序排列。pretty
参数告诉Elasticsearch返回格式良好的JSON结果。下面是部分返回结果:
{
"took" : 63,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1000,
"max_score" : null,
"hits" : [ {
"_index" : "bank",
"_type" : "account",
"_id" : "0",
"sort": [0],
"_score" : null,
"_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie"...}
}, {
"_index" : "bank",
"_type" : "account",
"_id" : "1",
"sort": [1],
"_score" : null,
"_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke"...}
}, ...
]
}
}
下面是一些返回的参数:
-
took
Elasticsearch执行搜索用的时间(毫秒数) -
timed_out
搜索是否超时 -
_shards
多少个切片被搜索,还有成功/失败的搜索切片数 -
hits
搜索结果 -
hits.total
搜索结果总数 -
hits.hits
实际搜索结果(默认是前10个文档) -
sort
用来排序的值(如果通过score排序则没有这个参数) -
_score
和max_score
暂时忽略
下面的搜索条件与上面搜索完全相同,但是使用request body method:
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}
重要的是一旦你接收到了搜索结果,Elasticsearch已经完成了请求不会保留任何服务端资源或者在你的结果里开放指针。
5.2 查询语言介绍
Elasticsearch提供了一个特定于域的JSON风格的语言来执行查询。这个查询语言是非常全面的甚至第一眼看时有点让人畏惧,最好的方式是从一些基本的例子开始学习。
回到上一个例子,我们执行以下查询:
GET /bank/_search
{
"query": { "match_all": {} }
}
query
部分指定我们的查询定义,match_all
部分是我们要查询的类型,match_all
表示在指定的索引中查询全部的文档。
除了query
参数,我们还可以传递另外一个参数来影响查询结果,之前我们传递的是sort
参数,这里我们传递size
:
GET /bank/_search
{
"query": { "match_all": {} },
"size": 1
}
size
表示每次查询返回的结果数量,这里只返回1条结果。注意:如果size
没有指定,默认值是10。
下面的例子表示从所有结果里查询第11-20之间的文档:
GET /bank/_search
{
"query": { "match_all": {} },
"from": 10,
"size": 10
}
from
参数是从0开始的,它指定了从那个文档索引开始查询,查询size个文档。这个特性可以用来实现分页。如果from
未指定,默认是0。
5.3 执行查询
我们已经看了一些基本的查询参数了,让我们更深入的了解下Query DSL。我们先看下搜索返回的_source
域,默认的被搜索到的文档会整体被作为结果的一部分返回来。如果我们不想整个文档被返回来,我们可以只请求文档中的部分资源被返回。
下面这个例子只返回account_number
和balance
字段:
GET /bank/_search
{
"query": { "match_all": {} },
"_source": ["account_number", "balance"]
}
这样返回的_source
里只有account_number
和balance
的数据。类似与SQL中的SELECT
的作用。
之前我们使用match_all
来查询所有的文档,下面我们来学习match query:
下面的例子查询account_number包含20的文档:
GET /bank/_search
{
"query": { "match": { "account_number": 20 } }
}
查询地址里有"mill"的所有文档:
GET /bank/_search
{
"query": { "match": { "address": "mill" } }
}
查询地址里有"mill"或者"lane"的所有文档:
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
match_phrase
是match
的一个变种,它会吧条件作为一个整体(短语),中间有空格不会被当做或者条件,我们查询下地址包含"mill lane"的文档:
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
下面我们介绍下bool(ean) query,bool query允许我们通过boolean
逻辑将一些小的查询组成一个大的查询。
下面这个例子组合两个match
查询,查询地址里包含"mill"和"lane"的所有文档:
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
这个例子里,bool
、must
条件指定了所有match
查询对于一个文档必须都是true时才返回。
下面这个例子组合两个match
查询,查询地址里包含"mill"或者"lane"的所有文档:
GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
这个例子里,bool
、must
条件指定了所有match
查询对于一个文档必须有一个是true时才返回。
下面这个例子组合两个match
查询,查询地址里即不包含"mill"也不包含"lane"的文档:
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
这个与must
类似,只是条件相反。
我们可以合并must
, should
, 和must_not
条件在一个bool
查询里。
下面的例子查询年龄是40岁,并且不住在ID(一个地名缩写):
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
5.4 执行过滤器
之前的章节里,我们跳过了一小段叫做document score(搜索结果里的_score
字段)。score是一个数字类型,表示文档相对于我们指定的搜索条件的匹配程度。分数越高,这个文档就越符合我们的搜索条件。
但是查询不一定每次都需要产生score,特别是我们仅对文档集进行筛选时。
bool query查询也支持filter
条件,作为一个例子我们介绍下range query,它允许我们通过一段值的范围来过滤文档集。它通常被用作数字和日期过滤。
下面的例子我们使用一个bool query返回所有账户余额大于等于20000并且小于等于30000之间的所有账户:
GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
现在介绍了match_all
, match
, bool
, 和 range
查询,还有许多类型的查询我们不会在这里继续介绍了。我们有了一个基本的理解后,学习其他类型的查询应该不是困难的。
5.5 执行聚合
聚合提供了分组和提取分析的能力。最简单的方法来理解就是与SQL中的GROUP BY和其他聚合函数类比。
在Elasticsearch里,你可以在一个搜索响应里同时接收执行搜索返回命中的结果和聚合结果。这是一个很强大的功能,在某些场景下你可以运行多个查询和多个聚合,并且在一个响应里同时接收两者的结果,这降低了与服务器之间的数据交互的次数。
现在我们将所有账户按照州来分组,并且返回最上面的10个州,按照每个分组的数量降序排列(默认的):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
如果用SQL语句则类似下面的语句:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
下面是返回结果(部分):
{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits" : {
"total" : 1000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_state" : {
"doc_count_error_upper_bound": 20,
"sum_other_doc_count": 770,
"buckets" : [ {
"key" : "ID",
"doc_count" : 27
}, {
"key" : "TX",
"doc_count" : 27
}, {
"key" : "AL",
"doc_count" : 25
}, {
"key" : "MD",
"doc_count" : 25
}, {
"key" : "TN",
"doc_count" : 23
}, {
"key" : "MA",
"doc_count" : 21
}, {
"key" : "NC",
"doc_count" : 21
}, {
"key" : "ND",
"doc_count" : 21
}, {
"key" : "ME",
"doc_count" : 20
}, {
"key" : "MO",
"doc_count" : 20
} ]
}
}
}
注意hits
的空的,因为我们只想看到聚合结果。
在前面查询的基础上,我们来计算下每个州的账户平均余额:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
注意我们是怎么在group_by_state
里嵌套average_balance
聚合的。这是所有聚合的一种通用模式。
先在让我在上面的查询里再修改下,默认的是按照每个分组的数量降序排列的,现在我们按照每个州的余额降序排列:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
接下来的例子示范了如何按照年龄分组(20-29, 30-39, 40-49),然后按照性别分组,最后计算每个年龄段,男女的平均余额:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_age": {
"range": {
"field": "age",
"ranges": [
{
"from": 20,
"to": 30
},
{
"from": 30,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
}
}
还有很多聚合的能力请参考aggregations reference guide
到此用户指南的入门部分结束。