原文地址:
https://www.elastic.co/guide/en/elasticsearch/reference/current/_exploring_your_data.html
搜索的REST API可以从_search端点访问。这个示例返回customer索引中的所有文档:
GET /event_search/_search?q=*&sort=id:asc&pretty
几个搜索参数的意思:
q=* :匹配索引中的所有文档
sort=id:asc : 所有文档按照id升序排序
pretty : 格式化JSON输出
响应如下:
{
"took" : 207,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 16107987,
"max_score" : null,
"hits" : [
{
"_index" : "event_search",
"_type" : "app_sjyx_event",
"_id" : "00000092-bda7-48de-80ef-1cee534aa5e7",
"_score" : null,
"_source" : {
"id" : "00000092-bda7-48de-80ef-1cee534aa5e7",
"event" : "wxid_winbzgzpq7fg12:我今天把超梦种族一弄"
},
"sort" : [
"00000092-bda7-48de-80ef-1cee534aa5e7"
]
},
{
"_index" : "event_search",
"_type" : "app_sjyx_event",
"_id" : "00000111-9a7c-483e-80fb-3313a4c9a8ce",
"_score" : null,
"_source" : {
"id" : "00000111-9a7c-483e-80fb-3313a4c9a8ce",
"event" : "通话时长 03:38"
},
"sort" : [
"00000111-9a7c-483e-80fb-3313a4c9a8ce"
]
}
]
}
}
关于响应,我们看到以下部分:
took – 搜索时间(毫秒)
timed_out – 搜索是否超时
_shards – 告诉我们搜索了多少碎片,以及成功/失败搜索碎片的计数
hits – 搜索结果
hits.total – 符合我们搜寻条件的文件总数
hits.hits – 实际的搜索结果数组(默认为前10个文档)
hits.sort 结果的排序键(如果按分数排序,则会丢失)
使用以下的方法可以达到相同的搜索结果:
POST /event_search/_search
{
"query": { "match_all": {} },
"sort": [
{ "id": "asc" }
]
}
很重要的一点是,一旦返回搜索结果,Elasticsearch就完全完成了对请求的处理,不会在结果中维护任何类型的服务器端资源或打开游标,这不同于SQL。
查询DSL是json风格的域特定查询语句,查询语句非常全面,我们先从几个基本的例子入手。
POST /event_search/_search
{
"query": { "match_all": {} },
"sort": [
{ "id": "asc" }
],
"from": 10,
"size": 10
}
搜索参数含义:
“query”:查询参数,match_all 指搜索所有的索引
“sort”:排序规则
“from”:指定从哪个文档索引开始,默认为0
“size”:指定从from参数开始返回多少文档
POST /event_search/_search
{
"query": { "match": { "event": "喜欢 推销" } },
"_source": ["id", "event"]
}
POST /event_search/_search
{
"query": { "match_phrase": { "event": "喜欢 推销" } }
}
由以上两例可以看出match
查询条件是或的关系,而match_phrase
查询条件是与的关系
bool查询允许我们使用布尔逻辑将较小的查询组合成较大的查询
以下例子包含两个匹配查询,并返回地址中包含“mill”和“lane”的所有帐户:
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
与此相反,这个示例包含两个匹配查询,并返回地址中包含“mill”或“lane”的所有帐户:
GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
这个示例包含两个匹配查询,并返回地址中既不包含“mill”也不包含“lane”的所有帐户:
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
这个示例返回所有40岁但不生活在ID(阿霍)中的人的帐户:
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
在上一节中,我们跳过了一个名为document score(搜索结果中的_score字段)的小细节。分数是一个数值,它是文档与我们指定的搜索查询匹配程度的相对度量。分数越高,文档越相关,分数越低,文档越不相关。
但是查询并不总是需要产生scores,特别是当它们仅用于“过滤”文档集时。Elasticsearch检测到这些情况并自动优化查询执行,以便不计算无用的分数。
我们在前一节中介绍的bool查询还支持filter子句,该子句允许使用查询来限制其他子句匹配的文档,而不改变计算分数的方式。作为一个例子,让我们引入range查询,它允许我们通过一系列值筛选文档。这通常用于数字或日期过滤。
以下示例使用bool查询返回所有余额在20000到30000之间的帐户(包括在内)。换句话说,我们希望找到的账户余额大于等于20000,小于等于30000:
GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
聚合提供了从数据中分组和提取统计信息的能力。考虑聚合最简单的方法是将其大致等同于SQL GROUP by和SQL聚合函数。在Elasticsearch中,您可以执行返回命中的搜索,同时在一个响应中返回与所有命中分离的聚合结果。这在某种意义上非常强大和高效,因为您可以运行查询和多个聚合,并一次性获得两个(或两个以上)操作的结果,从而减少网络资源调用的损耗。
首先,这个示例按状态对所有帐户进行分组,然后返回按计数递减排序的前10个(默认):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state"
}
}
}
}
在SQL中,上述聚合的概念类似于:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;
响应(部分显示):
{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped" : 0,
"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
} ]
}
}
}
我们可以看到ID(爱达荷州)有27个账户,TX(德克萨斯州)有27个账户,AL(阿拉巴马州)有25个账户,等等。
注意,我们将size=0
设置为不显示搜索结果,因为我们只想看到响应中的聚合结果。
注意我们如何将average_balance聚合嵌套到group_by_state聚合中。这是所有聚合的常见模式。
在前面的聚合的基础上,现在让我们按降序对平均余额进行排序:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state",
"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"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
}
}
还有很多其他的聚合功能我们在这里不会详细介绍。如果您想做进一步的实验,聚合参考指南是一个很好的起点。
Elasticsearch是一个简单的和复杂的产品。到目前为止,我们已经了解了它是什么,如何查看它的内部,以及如何使用一些REST api使用它。希望本教程能让您更好地理解Elasticsearch是什么,更重要的是,它激发了您对其其他强大功能的进一步试验!