ES入门:查询和聚合的基础使用
从索引文档开始
索引一个文档,向某个索引中插入一个文档。
PUT /customer/_doc/1
{
"name": "John Doe"
}
ES新文档插入图例
返回结果含义已经在截图中注解出来。
查询刚才插入的文档 GET /customer/_doc/1
输出结果为:
{
"_index": "customer",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"name": "John Doe"
}
}
学习准备:批量索引文档ES
ES 还提供了批量操作,比如这里我们可以使用批量操作来插入一些数据,供我们在后面学习使用。
使用批量来批处理文档操作比单独提交请求要快得多,因为它减少了网络往返。
- 下载测试数据
数据是index为bank,accounts.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"
}
- 批量插入数据
将accounts.json
拷贝至指定目录,我这里放在/opt/
下面, 然后执行
curl -v 'localhost:9200/bank/_bulk?format=yaml' -H 'Content-type: application/x-ndjson' --data-binary accounts.json
注意地址,替换里面路径。 如果按照上面的操作会遇到如下错误: 与ES版本有关系。
error:
root_cause:
- type: "illegal_argument_exception"
reason: "The bulk request must be terminated by a newline [\\n]"
type: "illegal_argument_exception"
reason: "The bulk request must be terminated by a newline [\\n]"
status: 400
解决上面的办法可以通过 postman
上传来解决。 插入成功后会返回执行的结果,返回结果是yaml
格式的数据:
took: 526
errors: false
items:
- index:
_index: "bank"
_type: "_doc"
_id: "1"
_version: 1
result: "created"
_shards:
total: 2
successful: 1
failed: 0
_seq_no: 0
_primary_term: 1
status: 201
查询数据
match_all
: 表示查询所有数据,sort
表示字段排序。
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}
返回结果如下:
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1000,
"relation": "eq"
},
"max_score": null,
"hits": [
{
"_index": "bank",
"_type": "_doc",
"_id": "0",
"_score": null,
"_source": {
"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"
},
"sort": [
0
]
},
... // 这里还有很多条
]
}
}
相关字段解释
took
– Elasticsearch运行查询所花费的时间(以毫秒为单位)timed_out
– 搜索请求是否超时_shards
- 搜索了多少个碎片,以及成功,失败或跳过了多少个碎片的细目分类。max_score
– 找到的最相关文档的分数hits.total.value
找到了多少个匹配的文档hits.sort
文档的排序位置(不按相关性得分排序时)hits._score
文档的相关性得分(使用match_all时不适用)
分页查询(from+size)
本质上就是from和size两个字段
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
],
"from": 10,
"size": 10
}
指定字段查询:match
如果要在字段中搜索特定字词,可以使用match
;
如下语句将查询address
字段中包含 mill
或者 lane
的数据
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
(由于ES底层是按照分词索引的,所以上述查询结果是address 字段中包含 mill 或者 lane的数据)
查询段落匹配:match_phrase
如果我们希望查询的条件是 address
字段中包含 "mill lane"
,则可以使用match_phrase
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
多条件查询: bool
如果要构造更复杂的查询,可以使用bool查询来组合多个查询条件。
例如,以下请求在bank索引中搜索40岁客户的帐户,但不包括居住在爱达荷州(ID)的任何人
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
must
, should
, must_not
和 filter
都是bool
查询的子句。
那么filter
和上述query
子句有啥区别呢?
查询条件:query or filter
先看下如下查询, 在bool
查询的子句中同时具备query/must
和 filter
{
"query": {
"bool": {
"must": [
{
"match": {
"state": "ND"
}
}
],
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
两者都可以写查询条件,而且语法也类似。区别在于:
query
上下文的条件是用来给文档打分的,匹配越好_score
越高;filter
的条件只产生两种结果:符合与不符合,后者被过滤掉。
所以,我们进一步看只包含filter的查询
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
结果,显然无_score
聚合查询:Aggregation
我们知道SQL中有group by,在ES中它叫Aggregation,即聚合运算。
比如我们希望计算出account
每个州的统计数量, 使用aggs
关键字对state
字段聚合,被聚合的字段无需对分词统计,所以使用state.keyword
对整个字段统计。
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
因为无需返回条件的具体数据, 所以设置size=0
,返回hits
为空。doc_count
表示bucket
中每个州的数据条数。
嵌套聚合
ES还可以处理个聚合条件的嵌套。
比如承接上个例子, 计算每个州的平均结余。涉及到的就是在对state
分组的基础上,嵌套计算avg(balance)
:
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
对聚合结果排序
可以通过在aggs
中对嵌套聚合的结果进行排序
比如承接上个例子, 对嵌套计算出的avg(balance)
,这里是average_balance
,进行排序。
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}