Elasticsearch用户指南 一 基础(2)

版本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"...}
    }, ...
    ]
  }
}

下面是一些返回的参数:

  • tookElasticsearch执行搜索用的时间(毫秒数)
  • timed_out搜索是否超时
  • _shards多少个切片被搜索,还有成功/失败的搜索切片数
  • hits搜索结果
  • hits.total搜索结果总数
  • hits.hits实际搜索结果(默认是前10个文档)
  • sort用来排序的值(如果通过score排序则没有这个参数)
  • _scoremax_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_numberbalance字段:

GET /bank/_search
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}

这样返回的_source里只有account_numberbalance的数据。类似与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_phrasematch的一个变种,它会吧条件作为一个整体(短语),中间有空格不会被当做或者条件,我们查询下地址包含"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" } }
      ]
    }
  }
}

这个例子里,boolmust条件指定了所有match查询对于一个文档必须都是true时才返回。

下面这个例子组合两个match查询,查询地址里包含"mill"或者"lane"的所有文档:

GET /bank/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}

这个例子里,boolmust条件指定了所有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

到此用户指南的入门部分结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 博客原文一博客原文二 翻译作品,水平有限,如有错误,烦请留言指正。原文请见 官网英文文档 起步 Elasticse...
    rabbitGYK阅读 3,228评论 0 68
  • 介绍查询语言 Elasticsearch提供一种JSON风格的特定领域语言,利用它你可以执行查询。这杯称为查询DS...
    山天大畜阅读 3,715评论 0 1
  • 探索你的数据 样本数据集 现在我们对于基本的东西已经有了一些感觉,现在让我们尝试使用一些更加贴近现实的数据集。我已...
    Jason__Ding阅读 404评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 一、因为刚好遇见你们 算是做出了一个改变,开学前便在班群里表现自己的活跃。我可不是初中那个畏畏缩缩的胆小鬼...
    平行四边形_阅读 232评论 0 0