elasticsearch6.7 01.入门指南(4)

5、Exploring Your Data(探索数据)

Sample Dataset(样本数据集)

现在我们已经学会了基础知识,让我们尝试在更真实的数据集上操作。我准备了一份顾客银行账户信息的虚构的 JSON 文档样本。每个文档都有以下的schema(模式):

{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "[email protected]",
    "city": "Hobucken",
    "state": "CO"
}

如果您对这份数据有兴趣,我从 www.json-generator.com/ 生成的这份数据,因为这些都是随机生成的,所以请忽略实际的值和数据的语义。

Loading the Sample Dataset(下载样本数据集)
您可以从这里下载这份样本数据集(accouts.json)。提取它到当前的目录,然后加载到集群中,如下所示 :

curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_bulk?pretty&refresh" --data-binary "@accounts.json"
curl "localhost:9200/_cat/indices?v"

响应如下 :

health status index uuid         pri rep docs.count docs.deleted store.size pri.store.size
yellow open   bank  l7sSYV2cQX 4  5   1       1000        0         128.6kb        128.6kb

这意味着我们刚才成功的批量索引了 1000 份文档到 bank索引(_doc类型下)。

5.1 The Search API(搜索 API)

现在让我们从一些简单的搜索开始。这里两个运行搜索的基本方法 : 一个是通过使用 REST请求URI 发送搜索参数,另一个是通过使用 REST请求体 来发送搜索参数。请求体的方法可以让您更具有表现力,并且可以在一个更可读的 JSON 格式中定义您的搜索。我们会尝试使用一个请求URI 的示例,但是在本教程的其它部分,我们将只使用请求体的方式。

搜索的 REST API 从_search的尾部开始。下例返回了bank索引中的所有文档 :

GET /bank/_search?q=*&sort=account_number:asc&pretty

首先让我们剖析搜索的调用。我们在 bank 索引中执行搜索(_search 尾部),然后 q=* 参数命令 Elasticsearch 去匹配索引中所有的文档。sort = account_number:asc参数指示使用每个文档中的account_number字段对结果进行升序排序。pretty 参数告诉 Elasticsearch 返回漂亮的 JSON 结果。

响应如下(部分):

{
  "took" : 63,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [ {
      "_index" : "bank",
      "_type" : "_doc",
      "_id" : "0",
      "sort": [0],
      "_score" : null,
      "_source" : {"account_number":0,"balance":16623,"firstname":"Bradshaw","lastname":"Mckenzie","age":29,"gender":"F","address":"244 Columbus Place","employer":"Euron","email":"[email protected]","city":"Hobucken","state":"CO"}
    }, {
      "_index" : "bank",
      "_type" : "_doc",
      "_id" : "1",
      "sort": [1],
      "_score" : null,
      "_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"[email protected]","city":"Brogan","state":"IL"}
    }, ...
    ]
  }
}

在响应中,我们可以看到以下几个部分 :

  • took : Elasticsearch 执行查询的时间,单位是毫秒
  • time_out : 查询是否超时
  • _shards :查询了多少个分片,其中有几个成功的,几个失败的
  • hits : 查询结果
  • hits.total : 总共有多少个文档满足查询条件
    • hits.total.value :总命中数的值(必须在hits.total.relation的上下文中解释)
    • hits.total.relationhits.total.value是否是确切的命中数,在这种情况下它等于“eq”。或总命中数的下限(大于或等于),在这种情况下它等于“gte
  • hits.hits: 实际的查询结果(数组形式表示,默认为前 10 个文档)
  • sort: 查询结果的排序字段(没有则按 score 排序)
  • scoremax_score:查询的得分,最高得分(现在暂时忽略这些字段)

hits.total的准确性由请求参数track_total_hits控制,当设置为true时,请求将准确跟踪总命中(“关系”:“eq”)。它默认为10,000,这意味着总命中数可以精确跟踪多达10,000个文档。您可以通过将track_total_hits显式设置为true来强制进行准确计数。有关详细信息,请参阅[request body]文档。

下例是对上面的搜索使用request 请求体方式进行的相同搜索: :

GET /bank/_search
{
    "query":{"match_all":{}},
    "sort":[
        {"account_number":"asc"}
    ]
}

这里的不同点就是用一个JSON风格的request请求体代替了q=*。我们将在下一部分讨论这个 JSON 查询。

一旦您搜索的结果被返回,Elasticsearch 便完成了这次请求,并且不会维护任何服务端的资源或者 cursor(游标)结果。这与其它的平台形成了鲜明的对比。例如在SQL中,您可以首先获得查询结果的子集,如果您想要使用一些服务端有状态的 cursor(光标)来抓取(或者通过分页)其它的结果,您必须再次回到服务器。

5.2 Introducing the Query Language(介绍查询语言)

Elasticsearch 提供了一个可以执行查询的 Json 风格的语句。这个被称为 Query DSL(domain-specific language 领域特定语言)。该查询语言非常全面,可能刚开始学的时候会感觉有点复杂,学习它的最好方式是从一些基础的示例开始。

回到上个例子,我们执行了这个查询 :

GET /bank/_search
{
    "query":{"match_all":{}}
}

分析上面的查询,query 部分告诉我们查询是如何定义的,match_all 部分就是我们要运行的查询类型。match_all表示查询索引中的所有文档。

除了query参数之外,我们也可以传递其它的参数以改变查询结果。在上部分的例子中我们传递了sort,下例我们传递size :

GET /bank/_search
{
    "query":{"match_all":{}},
    "size":1
}

注意,如果不指定 size,其默认值为 10.

下例做了一个match_all并且返回第10~19 的文档。

GET /bank/_search
{
    "query":{"match":{}},
    "from": 10,
    "size": 10
}

from 参数指定的是从第几条记录开始返回,其默认值为0,size参数指定的是返回结果的条数。在实现分页搜索时这个功能是很有用的。

下面的例子做了一个 match_all,结果按balance降序排序且返回了前10(默认大小)个文档。

GET /bank/_search
{
    "query":{"match_all":{}},
    "sort":{"balance":{"order":"desc"}}
}

5.3 Executing Searches(执行查询)

现在我们已经了解了基本的搜索参数,让我们深入探讨更多的 DSL。我们首先看一下返回的文档字段。默认情况下,完整的 JSON 文档会被作为所有搜索的一部分返回。这被称为“source”(hits 中的_source 字段)。如果我们不希望返回整个 source 文档,我们可以只请求返回 source 中的一些字段。

下例演示了如何从搜索中返回account_numberbalance(在 _source 之内)字段,如下所示 :

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

注意,上面的的响应中将只有一个_source字段,并且里面只有account_numberbalance两个字段。如果你会SQL语句,那么这个请求就类似于SQL中的SELECT FROM 字段列表

现在让我们继续关注query部分。此前,我们了解了 match_all 是如何查询所有文档的。我们现在介绍一个名为 match query 的新查询,它可以被视为基本的字段化搜索查询(例如,针对一个指定字段或一组字段来搜索)。

下面例子返回了account_number为 20 的文档 :

GET /bank/_search
{
    "query":{"match":{"account_number":20}}
}

下面例子返回了在address中包含mill 的账户 :

GET /bank/_search
{
    "quer":{"match":{"address":"mill"}}
}

下面例子返回了在address中包含了 milllane的账户 :

GET /bank/_search
{
    "query":{"match":{"address":"mill lane"}}
}

下面例子是math(match_phrase)的另一种方式,它返回了在 address中所有包含mill lane 的账户 :

GET /bank/_search
{
    "query":{"match_phrase":{"address":"mill lane"}}
}

现在我们介绍 bool query。bool查询允许我们组合使用布尔逻辑。
下面例子构建两个 match查询,并且返回了在 address中包含了milllane的账户 :

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

这个例子中要求must大括号里面的查询条件必须都为真,才认为满足查询条件。

相反,下面这个例子用should组装两个match条件,返回的结果将是address字段里面包含mill或是包含lane的记录:

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

下面例子构建两个match 查询,并且回了在 address 中既不包含 “mill” 也不包含 “lane” 的账户 :

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

这个例子中要求must_not大括号里面的查询条件都为false。

我们可以在 bool 查询中同时联合 mustshouldmust_not语句。此外,我们可以在任何一个bool语句内部构建bool查询,从而模拟出任何复杂的多级别的 boolean 逻辑。

下面的例子返回了age40 但是 state不为ID的账户 :

GET /bank/_search
{
    "query":{
        "bool":{
            "must":[
                {"match":{"age":40}}
             ],
            "must_not":[
                {"match":{"state":"ID"}}
            ]
        }
     }
}

5.4 Executing Filters(执行过滤)

在上一节中,我们跳过了一些名为score(在搜索结果中的 _score 字段)的细节。score是一个数值,它是文档与我们指定的搜索查询匹配程度的相对度量。分数越高,文档的相关度更高,分数越低,文档的相关度越低。

并不是所有的查询都需要产生分数,特别是当它们只用于filtering文档集时。ElasticSearch检测到这些情况,并自动优化查询执行,以避免计算无用的分数。

在上一节中我们介绍的 bool 查询也支持 filter 子句,这些子句允许我们使用查询来限制将与其他子句匹配的文档,而不会更改计算得分的方式。举个例子,让我们介绍下range查询,它可以让我们通过一系列的值过滤文档。这通常用于数字或者日期过滤。

下面的例子使用了一个 bool 查询来返回balances20000 ~ 30000 之间的账户(包含 20000 和 30000)。换言之,我们想要去找出balances大于或等于 20000 且小于或等于 30000 的账户。

GET /bank/_search
{
    "query":{
        "bool":{
            "must":{"match_all":{}},
            "filter:{
                "range":{
                    "balance":{
                        "gte":20000,
                        "lte":30000
                    }
                }
            }
        }
    }
}

分析上面的结构,bool 查询包含了一个 match_all 查询(query部分),和一个 range(范围)查询(filter部分)。我们可以将任何其他查询替换为query和filter部分。在上述情况下,range范围内的文档相当于匹配,即没有文档比范围内的文档更相关。

除了 match_allmatchboolrange查询之外 ,还有很多在这里我们我没有用到的其它有用的查询类型。既然我们对于它们是如何工作的方式有了一个基本的了解,在学习和尝试其它的查询类型中应用这些知识应该不会太困难。

5.5 Executing Aggregations(执行聚合)

aggregations提供了从数据中分组和统计数据的能力。最简单的聚合方法大致等同于SQL的group by 和SQL的聚合函数。在elasticsearch中,您可以同时执行查询和聚合的结果。这是非常强大且有效的,您可以执行查询和多个聚合,并且在一次请求中得到各自的(任何一个的)返回结果,避免频繁的网络请求。

首先,下面的例子是对所有account按照state进行分组,然后返回按计数降序排序的前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 LIMIT 10;

响应如下(部分显示):

{
  "took": 29,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped" : 0,
    "failed": 0
  },
  "hits" : {
     "total" : {
        "value": 1000,
        "relation": "eq"
     },
    "max_score" : null,
    "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(Idaho)有 27 个 account(账户),在 TX(Texas)有 27 个 account(账户),在 AL(Alabama)有25 个账户等等。

注意我们设置了size=0 以不显示搜索结果,因为我们只希望在响应中看聚合结果。

基于前面的聚合,下面的例子按state计算了平均的账户balance(同样,仅针对按计数降序排序的前10个状态 ):

GET /bank/_search
{
    "size":0,
    "aggs":{
        "group_by_state":{
            "terms":{
                "fields":"state.keyword"
            },
            "aggs":{
                "average_balanece":{
                    "avg":{
                        "field":"balance"
                    }
                }
            }
        }
    }
}

请注意,我们如何将average_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"
                     }
                }
            }
        }
    }
}

下面的例子演示了我们如何按age(20-29岁,30-39岁,和 40-49岁)分组,然后按gender分组,最后获得每个年龄段每个性别的平均账户余额 :

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"
              }
            }
          }
        }
      }
    }
  }
}

还有一些我们这里没有细讲的其它的聚合功能。如果您想要做进一步的实验,聚合参考指南是一个比较好的起点。

6、Conclusion(总结)

Elasticsearch 既是一个简单,又是一个复杂的产品。我们现在学会了它的基础部分,如何去看它内部,以及如何使用一些 REST API 来操作它。我希望本教程可以让您更好的了解 Elasticsearch 是什么,更重要的是,可以促使你进一步尝试它更强大的功能。

原文地址:https://www.cnblogs.com/wtc1994/p/10703598.html

时间: 2024-10-21 09:28:47

elasticsearch6.7 01.入门指南(4)的相关文章

elasticsearch6.7 01.入门指南(2)

目录 2.安装(略) 3.探索集群 3.1 The REST API 3.2. Cluster Health(集群健康) 3.3 List All Indices(查看所有索引) 3.4 Create an Index(创建索引) 3.5 索引和查询文档 3.6 Delete an Index(删除索引) 2.安装(略) 默认情况下,elasticsearch 使用端口 9200 来访问它的 REST API.如果有必要,该端口也可以配置 3.探索集群 3.1 The REST API 既然我们

AngularJS快速入门指南01:导言

AngularJS使用新的attributes扩展了HTML AngularJS对单页面应用的支持非常好(SPAs) AngularJS非常容易学习 现在就开始学习AngularJS吧! 关于本指南 本指南旨在帮助你尽可能快速而有效地学习AngularJS.通过该指南你会学习到AngularJS的一些基本特性,例如指令.表达式.过滤器.模块和控制器等.以及其它所有你需要知道的有关AngularJS的东西,如事件.DOM节点.表单.用户输入.数据验证.Http对象等. AngularJS快速入门指

Asp.Net MVC4入门指南(8):给数据模型添加校验器

在本节中将会给Movie模型添加验证逻辑.并且确保这些验证规则在用户创建或编辑电影时被执行. 保持事情 DRY ASP.NET MVC 的核心设计信条之一是DRY: "不要重复自己(Don't Repeat Yourself)".ASP.NET MVC鼓励您指定功能或者行为,只做一次,然后将它应用到应用程序的各个地方.这可以减少您需要编写的代码量,并减少代码出错率,易于代码维护. 给ASP.NET MVC 和 Entity Framework Code First 提供验证支持是 DR

Asp.Net MVC4入门指南(9):查询详细信息和删除记录

在本教程中,您将查看自动生成的Details和Delete方法. 查询详细信息和删除记录 打开Movie控制器并查看Details方法. public ActionResult Details(int id = 0) { Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } Code First 使得您可以轻松的使用Find方法来搜索数据.一个重要

AngularJS快速入门指南02:介绍

AngularJS是一个JavaScript框架.它可以通过<script>标记被添加到HTML页面中. AngularJS通过指令对HTML属性进行了扩展,然后通过表达式将数据绑定到HTML元素中. AngularJS是一个JavaScript框架 AngularJS是一个JavaScript框架,它是由JavaScript语言编写的类库. AngularJS以JavaScript文件的形式进行发布,我们可以通过script标记将它添加到web页面中: <script src=&quo

Asp.Net MVC4入门指南(5):从控制器访问数据模型

在本节中,您将创建一个新的MoviesController类,并在这个Controller类里编写代码来取得电影数据,并使用视图模板将数据展示在浏览器里. 在开始下一步前,先Build一下应用程序(生成应用程序)(确保应用程序编译没有问题) 用鼠标右键单击Controller文件夹,并创建一个新的 MoviesController控制器.当Build成功后,会出现下面的选项.设定以下选项: · 控制器名称: MoviesController.(这是默认值). · 模板: MVC Controll

Asp.Net MVC4入门指南(7):给电影表和模型添加新字段

在本节中,您将使用Entity Framework Code First来实现模型类上的操作.从而使得这些操作和变更,可以应用到数据库中. 默认情况下,就像您在之前的教程中所作的那样,使用 Entity Framework Code First自动创建一个数据库,Code First为数据库所添加的表,将帮助您跟踪数据库是否和从它生成的模型类是同步的.如果他们不是同步的,Entity Framework将抛出一个错误.这非常方便的在开发时就可以发现错误,否则您可能会在运行时才发现这个问题. (由

Asp.Net MVC4入门指南(4):添加一个模型

在本节中,您将添加一些类,这些类用于管理数据库中的电影.这些类是ASP.NET MVC 应用程序中的"模型(Model)". 您将使用.NET Framework 数据访问技术Entity Framework,来定义和使用这些模型类.Entity Framework(通常称为 EF) 是支持代码优先的开发模式.代码优先允许您通过编写简单的类来创建对象模型.(相对于"原始的CLR objects",这也被称为POCO 类)然后可以从您的类创建数据库,这是一个非常干净快

Asp.Net MVC4入门指南(3):添加一个视图

在本节中,您需要修改HelloWorldController类,从而使用视图模板文件,干净优雅的封装生成返回到客户端浏览器HTML的过程. 您将创建一个视图模板文件,其中使用了ASP.NET MVC 3所引入的Razor视图引擎.Razor视图模板文件使用.cshtml文件扩展名,并提供了一个优雅的方式来使用C#语言创建所要输出的HTML.用Razor编写一个视图模板文件时,将所需的字符和键盘敲击数量降到了最低,并实现了快速,流畅的编码工作流程. 当前在控制器类中的Index方法返回了一个硬编码