elasticsearch 开始 —— 探索你的数据

exploring your data 探索你的数据


现在我们对elasticsearch已经有了简单的认识,下面让我们尝试一个更真实的数据。我们准备了一份客户银行帐户信息的虚拟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"
}

加载简单的数据集:
你可以从这里下载用到的数据。将数据下载到某个目录,然后使用如下方式将数据加载到elasticsearch中:
curl -XPOST 'localhost:9200/bank/account/_bulk?pretty' --data-binary @accounts.json
curl 'localhost:9200/_cat/indices?v'
响应如下:
curl 'localhost:9200/_cat/indices?v'
health index pri rep docs.count docs.deleted store.size pri.store.size
yellow bank    5   1       1000            0    424.4kb        424.4kb

这意味着我们刚刚成功地批量索引1000个文档到银行索引中(根据帐户类型)。

the search api 搜索 API

让我们从几个基本的搜索开始。在elasticsearch中搜索有两种方式,一种是通过 REST request API 发送搜索参数,另一种是通过 REST request Body. 第二种方法将你的搜索请求表达为可读的JSON格式,更富有表现力。下面我们将使用第一种请求URL方法来进行基本的搜索。请求体方法将会是一个单独的篇章。
搜索的REST API,是通过 _search 来访问的。下面的示例返回了bank索引中所有的文档:
<span style="font-size:14px;">curl 'localhost:9200/bank/_search?q=*&pretty'</span>

让我们先来剖析一下搜索调用。我们是在bank索引中搜索的,q=* 参数指示elasticsearch匹配该索引下的所有文档。pretty参数再一次出现,用于告诉elasticsearch返回一个格式良好的JSON结果。
响应的结果(部分):
<span style="font-size:14px;">curl 'localhost:9200/bank/_search?q=*&pretty'
{
  "took" : 63,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "1",
      "_score" : 1.0, "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
    }, {
      "_index" : "bank",
      "_type" : "account",
      "_id" : "6",
      "_score" : 1.0, "_source" : {"account_number":6,"balance":5686,"firstname":"Hattie","lastname":"Bond","age":36,"gender":"M","address":"671 Bristol Street","employer":"Netagy","email":"hattiebond@netagy.com","city":"Dante","state":"TN"}
    }, {
      "_index" : "bank",
      "_type" : "account",</span>

观察响应结果,发现由以下几部分组成:
  • took   elasticsearch 执行搜索花费的时间 (毫秒)
  • time_out  告诉我们搜索是否超时
  • _shards 指示多少分片被搜索了,以及成功和失败的分片
  • hits 搜索结果个数
  • hits.total 匹配搜索词的文档个数
  • hits.hits 搜索结果的实际数组列表(默认为前10个文档) 
  • _score , max_score  (暂时忽略这两个域的意思)
下面是使用请求体的方式来执行上述搜索:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} }
}'</span>

不同于之前的搜索方式的是,我们POST 一个JSON格式的请求体到 _search API。下一节,我们将讨论JSON格式的请求方式。
需要注意的是,一旦elasticsearch 完成一个搜索请求后,它不会再维护任何与之有关的服务器资源,或者指向搜索结果的游标。

introducing the query language 介绍查询语言

Elasticsearch 提供了一种JSON风格的领域特定语言用于执行搜索。这被称之为 Query DSL。 查询语言非常全面,一开始接触可能会被吓到,但是最好的学习它的方式就是从最基本的例子开始。回到我们最后执行的一次查询:
<span style="font-size:14px;">{
  "query": { "match_all": {} }
}</span>
剖析上述命令,query部分指示定义的查询是什么,match_all 部分是我们期望查询的类型,亦即查询一个索引下所有的文档。除了 query这个参数以外,我们还可以传递一些其它的参数来影响查询结果。例如下面的示例,查询所有文档,但只返回第一个结果:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "size": 1
}'</span>
注意,如果size没有被指定,那么默认是10.
下面的示例,执行查询所有文档,但返回11到20之间的结果:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}'</span>

from参数指定从第几个索引的文档开始,size参数返回从from参数指定的文档后的数量。这个功能是非常有用的,当需要实现结果分页的时候。当from参数未指定时,默认为0.
下面的示例执行查询所有的文档,并将结果按照balance域降序排列,并返回前10个结果。
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}'</span>

executing searches 执行搜索

现在,我们已经看到了一些基本的搜索参数,让我们深入挖掘Query DSL。让我们先来看看在返回的文档中的字段。默认情况下,整个的JSON文档会作为搜索结果的一部分被返回。如果我们不想让源文档作为返回结果中的一部分,那么我们就需要有搜索指定字段的能力。
这个例子显示了如何返回两个字段,account_number 和balance(在 _source内的):

<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}'</span>

上面的例子仍然会返回一个包含_source域的结果,但是_source域里只有两个域 account_number 和 balance.
现在,让我们讨论query部分。此前,我们已经看到了match_all是如何用来匹配所有文档的。现在,让我们引入一个新的查询方式 match,它可以被看作是一个基本的搜索查询(完成对一个特定字段或字段集的搜索)。
此示例返回编号为20的帐户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "account_number": 20 } }
}'</span>

这个例子会返回一个地址中包含的“mill”一词的所有帐户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "address": "mill" } }
}'</span>
这个例子会返回一个地址中包含的“mill”或者"lane"的所有帐户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match": { "address": "mill lane" } }
}'</span>

这个例子是 match(match_phrase)的一个变种,它返回地址中包含"mill lane" 的所有账户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": { "match_phrase": { "address": "mill lane" } }
}'</span>

现在让我们介绍 bool(ean) 查询,布尔查询允许我们将小的查询语句通过布尔逻辑组合称较大的查询语句。
这个例子将两个子查询结合在一起来查询地址中包含 "mill" 与 "lane" 的所有账户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}'</span>

上面的查询中 bool must 字句要求每一个文档必须匹配match 中的两个条件。

下面这个例子将两个子查询结合在一起来查询地址中包含 "mill" 或 "lane" 的所有账户:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}'</span>
上面的查询中 bool should 字句要求每一个文档匹配match 中的两个条件之一或者都匹配。
我们可以将 must , must_not, shoud 联合起来用在一个bool查询中,进一步,我们可以嵌套bool查询。

此示例返回是40岁,但不居住在ID(DAHO)的所有帐户:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}'

executing filters 执行过滤器

在之前的章节中,我们忽略了一个细节,那就是文档得分(score), 文档得分是一个数值,它用于衡量搜索结果与查询语句的匹配程度。得分越高,代表相关度越高,得分越低,代表相关度越低。
在elasticsearch中,所有的搜索请求都会触发相关得分的计算,但是有些情况下,我们并不需要计算相关得分。elasticsearch提供了另一种使用过滤器的查询方式。过滤器类似于概念上的查询,不同的是它们拥有更快的执行速度,主要有两个原因:
  • 过滤器不必计算相关得分,所以它比普通查询快
  • 过滤器可以缓存在内存中,相比于普通查询,重复搜索的执行会显著加快
要了解过滤器,首先我们介绍 filtered query 它允许你将普通查询(match, match_all, bool) 等与过滤器联合起来。作为例子,我们介绍一下 range filter, 它允许你按照值的范围来过滤文档,通常用于日期或者数字过滤。
下面的例子会返回一个balance在 20000 ~ 30000之间的所有账户,包括边界。
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "query": {
    "filtered": {
      "query": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}'</span>
剖析上述例子,我们使用了一个filtered query,包括一个 query 和 filter。我们可以使用任何filter替换例子中的分filter,也可以用任何query替换例子中的query。

通常情况下,使用filtered query 还是普通 query 取决于你的选择。如果相关度对你来说很重要则使用普通的查询,如果不重要,则使用 filtered query.
除了 match_all, match, bool, filtered query以外,还有很多查询类型。在这里不再细说。相信你已经对这些方法的使用有了基本的了解。在此基础上学习其它的查询类型应该不难。

executing aggregations 执行汇总

汇总提供了将搜索结果分组以及对结果进行统计的能力。理解汇总的最好的方法是对比SQL语句中的 GROUP BY 以及SQL的汇总函数.
下面的例子,将所有的账户按照国家汇总分组,并按照汇总计数降序排列:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state"
      }
    }
  }
}'</span>

上述命令在SQL 中好比:
<span style="font-size:14px;">SELECT COUNT(*) from bank GROUP BY state ORDER BY COUNT(*) DESC</span>

返回结果:
<span style="font-size:14px;"> "hits" : {
    "total" : 1000,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_state" : {
      "buckets" : [ {
        "key" : "al",
        "doc_count" : 21
      }, {
        "key" : "tx",
        "doc_count" : 17
      }, {
        "key" : "id",
        "doc_count" : 15
      }, {
        "key" : "ma",
        "doc_count" : 15
      }, {
        "key" : "md",
        "doc_count" : 15
      }, {
        "key" : "pa",
        "doc_count" : 15
      }, {
        "key" : "dc",
        "doc_count" : 14
      }, {
        "key" : "me",
        "doc_count" : 14
      }, {
        "key" : "mo",
        "doc_count" : 14
      }, {
        "key" : "nd",
        "doc_count" : 14
      } ]
    }
  }
}</span>

我们可以看到,有21个账户在AL,其次是17个帐户在TX,其次是有15个账户在ID ,等等。注意我们将size设置为0用于屏蔽命中结果,因为我们只需要显示聚合结果。
建立在以前的聚合查询上,这个例子计算按照国家(州)分组后的每个国家(州)的平均账户余额(再次按照排名前10位国家降序排列):

<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}'</span>

注意我们是如何将average_balance 嵌套在group_by_state中的,这是聚合查询的基本模式。你可以随意的嵌套以便于从待考察的数据中提取出你想要的统计结果。
在前面的基础上,让我们降序排列平均余额:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}'</span>

此示例演示我们如何先按照年龄段分组(年龄20-29,30-29,40-49...),然后按性别,然后得到每个年龄段,每个性别的平均账户余额:
<span style="font-size:14px;">curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
  "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"
              }
            }
          }
        }
      }
    }
  }
}'</span>

还有许多汇总查询的使用方式,这里不再详述。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值