• Elasticsearch 教程--入门


    1.1 初识

    Elasticsearch 是一个建立在全文搜索引擎 Apache Lucene(TM) 基础上的搜索引擎,可以说 Lucene 是当今最先进,最高效的全功能开源搜索引擎框架。

    但是 Lucene 只是一个框架,要充分利用它的功能,你需要使用 JAVA,并且在你的程序中集成 Lucene。更糟的是,你需要做很多的学习了解,才能明白它是如何运行的,Lucene 确实非常复杂。

    Elasticsearch 使用 Lucene 作为内部引擎,但是在你使用它做全文搜索时,只需要使用统一开发好的API即可,而并不需要了解其背后复杂的 Lucene 的运行原理。

    当然 Elasticsearch 并不仅仅是 Lucene 那么简单,它不仅包括了全文搜索功能,还可以进行以下工作:

      • 分布式实时文件存储,并将每一个字段都编入索引,使其可以被搜索。
      • 实时分析的分布式搜索引擎。
      • 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。

    这么多的功能被集成到一台服务器上,你可以轻松地通过客户端或者任何你喜欢的程序语言与 ES 的 RESTful API 进行交流。

    Elasticsearch 的上手是非常简单的。它附带了很多非常合理的默认值,这让初学者很好地避免一上手就要面对复杂的理论,它安装好了就可以使用了,用很小的学习成本就可以变得很有生产力。

    随着学习的深入,你还可以使用 Elasticsearch 更多高级的功能,整个引擎可以很灵活地进行配置。你可以根据自身需求来定制属于你自己的 Elasticsearch。

    1.2 安装

    安装 JAVA

    yum install java-1.7.0-openjdk -y
    

    安装 Elasticsearch

    了解 Elasticsearch 最简单的方法就是去尽情的玩儿它(汗),准备好了我们就开始吧。

    安装 Elasticsearch 只有一个要求,就是要安装最新版本的JAVA。你可以到官方网站下载它:www.java.com.

    你可以在这里下载到最新版本的 Elasticsearch: elasticsearch.org/download.

    curl -L -O http://download.elasticsearch.org/PATH/TO/LATEST/$VERSION.zip
    unzip elasticsearch-$VERSION.zip
    cd  elasticsearch-$VERSION
    

    提示: 当你安装 Elasticsearch 时,你可以到 下载页面 选择Debian或者RP安装包。或者你也可以使用官方提供的 Puppet module 或者 Chef cookbook.

    安装 Marvel

    这是个付费的监控插件 暂时先不翻译

    Marvel is a management and monitoring tool for Elasticsearch which is free for development use. It comes with an interactive console called Sense which makes it very easy to talk to Elasticsearch directly from your browser.

    Many of the code examples in this book include a ``View in Sense'' link. When clicked, it will open up a working example of the code in the Sense console. You do not have to install Marvel, but it will make this book much more interactive by allowing you to experiment with the code samples on your local Elasticsearch cluster.

    Marvel is available as a plugin. To download and install it, run this command in the Elasticsearch directory:

    ./bin/plugin -i elasticsearch/marvel/latest
    

    You probably don't want Marvel to monitor your local cluster, so you can disable data collection with this command:

    echo 'marvel.agent.enabled: false' >> ./config/elasticsearch.yml
    

    运行 Elasticsearch

    Elasticsearch 已经蓄势待发,现在你便可以运行它了:

    ./bin/elasticsearch
    

    如果你想让它在后台保持运行的话可以在命令后面再加一个 -d

    开启后你就可以使用另一个终端窗口来进行测试了:

    curl 'http://localhost:9200/?pretty'
    

    你应该看到如下提示:

    {
       "status": 200,
       "name": "Shrunken Bones",
       "version": {
          "number": "1.4.0",
          "lucene_version": "4.10"
       },
       "tagline": "You Know, for Search"
    }
    

    这就说明你的 Elasticsearch 集群 已经上线运行了,这时我们就可以进行各种实验了。


    集群和节点

    节点 是 Elasticsearch 运行的实例。集群 是一组有着同样cluster.name的节点,它们协同工作,互相分享数据,提供了故障转移和扩展的功能。当然一个节点也可以是一个集群。

    1.3 API

    与 Elasticsearch 通信

    如何与 Elasticsearch 通信要取决于你是否使用 JAVA。

    Java API

    如果你使用的是 JAVA,Elasticsearch 内置了两个客户端,你可以在你的代码中使用:

    节点客户端: 节点客户端以一个 无数据节点 的身份加入了一个集群。换句话说,它自身是没有任何数据的,但是他知道什么数据在集群中的哪一个节点上,然后就可以请求转发到正确的节点上并进行连接。

    传输客户端: 更加轻量的传输客户端可以被用来向远程集群发送请求。他并不加入集群本身,而是把请求转发到集群中的节点。

    这两个客户端都使用 Elasticsearch 的 传输 协议,通过9300端口与 java 客户端进行通信。集群中的各个节点也是通过9300端口进行通信。如果这个端口被禁止了,那么你的节点们将不能组成一个集群。


    TIP

    Java 的客户端的版本号必须要与 Elasticsearch 节点所用的版本号一样,不然他们之间可能无法识别。


    更多关于 Java API 的说明可以在这里找到 Guide.

    通过 HTTP 向 RESTful API 传送 json

    其他的语言可以通过9200端口与 Elasticsearch 的 RESTful API 进行通信。事实上,如你所见,你甚至可以使用行命令 curl 来与 Elasticsearch 通信。


    Elasticsearch 官方提供了很多种编程语言的客户端,也有和许多社区化软件的集成插件,这些都可以在Guide 里面找到。


    向 Elasticsearch 发出的请求和其他所有的 HTTP 请求的组成部分是一致的。例如,计算集群中文件的数量,我们就可以使用:

    <1> <2> <3> <4> curl -XGET 'http://localhost:9200/_count?pretty' -d ' { <5> "query": { "match_all": {} } } '

      1. 相应的 HTTP 请求方法 或者 变量 : GETPOSTPUTHEAD 或者 DELETE

      2. 集群中任意一个节点的访问协议、主机名以及端口。

      3. 请求的路径。

      4. 任意一个查询后再加上 ?pretty 就可以生成 更加美观 的JSON反馈,以增强可读性。

      5. 一个 JSON 编码的请求主体(如果需要的话)。

    Elasticsearch 将会返回一个 HTTP 状态码类似于 '200 OK',以及一个 JSON 格式的主体(除了单纯的 'HEAD' 请求),上面的请求会得到下方的 JSON 主体:

    { "count" : 0, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 } }

    在反馈中,我们并没有看见 HTTP 的头部信息,因为我们没有告知 curl 显示这些内容。如果你想看到头部信息,可以在使用 curl 命令的时候再加上 -i 这个参数:

    curl -i -XGET 'localhost:9200/'

    从现在开始,本书里所有涉及 curl 命令的部分我们都会进行简写,因为主机、端口等信息都是相同的,缩减前的样子:

    curl -XGET 'localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }'

    我们将会简写成这样:

    GET /_count { "query": { "match_all": {} } }

    1.4 文档

    面向文档

    程序中的对象很少是单纯的键值与数值的列表。更多的时候它拥有一个复杂的结构,比如包含了日期、地理位置、对象、数组等。

    迟早你会把这些对象存储在数据库中。你会试图将这些丰富而又庞大的数据都放到一个由行与列组成的关系数据库中,然后你不得不根据每个字段的格式来调整数据,然后每次重建它你都要检索一遍数据。

    Elasticsearch 是 面向文档型数据库,这意味着它存储的是整个对象或者 文档,它不但会存储它们,还会为他们建立索引,这样你就可以搜索他们了。你可以在 Elasticsearch 中索引、搜索、排序和过滤这些文档。不需要成行成列的数据。这将会是完全不同的一种面对数据的思考方式,这也是为什么 Elasticsearch 可以执行复杂的全文搜索的原因。

    JSON

    Elasticsearch使用 JSON (或称作JavaScript Object Notation ) 作为文档序列化的格式。JSON 已经被大多数语言支持,也成为 NoSQL 领域的一个标准格式。它简单、简洁、易于阅读。

    把这个 JSON 想象成一个用户对象:

    {
        "email":      "john@smith.com",
        "first_name": "John",
        "last_name":  "Smith",
        "about": {
            "bio":         "Eco-warrior and defender of the weak",
            "age":         25,
            "interests": [ "dolphins", "whales" ]
        },
        "join_date": "2014/05/01",
    }
    

    虽然 user 这个对象非常复杂,但是它的结构和含义都被保留到 JSON 中了。在 Elasticsearch 中,将对象转换为 JSON 并作为索引要比在表结构中做相同的事情简单多了。


    将你的数据转换为 JSON

    几乎所有的语言都有将任意数据转换、机构化成 JSON,或者将对象转换为JSON的模块。查看 serialization 以及marshalling 两个 JSON 模块。The official Elasticsearch clients 也可以帮你自动结构化 JSON。

    1.5 索引

    启程

    为了能让你感受一下 Elasticsearch 能做什么以及它是有多么的易用,我们会先为你简单展示一下,其中包括了基本的 创建索引搜索 以及 聚合

    我们会在这里向你介绍一些新的术语以及简单的概念,即使你没有马上接受这些概念也没有关系。我们会在之后的章节中逐渐帮你理解它们。

    所以,准备开始享受 Elasticsearch 的学习之旅把!

    建立一个员工名单

    想象我们正在为一个名叫 megacorp 的公司的 HR 部门制作一个新的员工名单系统,这些名单应该可以满足实时协同工作,所以它应该可以满足以下要求:

      • 数据可以包含多个值的标签、数字以及纯文本内容,
      • 可以检索任何职员的所有数据。
      • 允许结构化搜索。例如,查找30岁以上的员工。
      • 允许简单的全文搜索以及相对复杂的短语搜索。
      • 在返回的匹配文档中高亮关键字。
      • 拥有数据统计与管理的后台。

    为员工档案创建索引

    这个项目的第一步就是存储员工的数据。这样你就需要一个“员工档案”的表单,这样每个文档都代表着一个员工。在 Elasticsearch 中,存储数据的行为就叫做 索引(indexing) ,但是在我们索引数据前,我们需要决定将数据存储在哪里。

    在 Elasticsearch 中,文档属于一种 类型(type),各种各样的类型存在于一个 索引 中。你也可以通过类比传统的关系数据库得到一些大致的相似之处:

    关系数据库     ⇒ 数据库 ⇒ 表    ⇒ 行    ⇒ 列(Columns)
    Elasticsearch  ⇒ 索引   ⇒ 类型  ⇒ 文档  ⇒ 字段(Fields)
    

    一个 Elasticsearch 集群可以包含多个 索引(数据库),也就是说其中包含了很多 类型(表)。这些类型中包含了很多的 文档(行),然后每个文档中又包含了很多的 字段(列)。


    索引 索引 索引

    你可能发现在 Elasticsearch 中,索引这个词汇已经被赋予了太多意义,所以在这里我们有必要澄清一下:

    索引 (名词)

    如上文所说,一个 索引 就类似于传统关系型数据库中的 数据库。这里就是存储相关文档的的地方。

    索引 (动词)

    为一个文档创建索引 是把一个文档存储到一个索引(名词)中的过程,这样它才能被检索。这个过程非常类似于 SQL 中的 INSERT 命令,如果已经存在文档,新的文档将会覆盖旧的文档。

    反向索引

    在关系数据库中的某列添加一个 索引,比如多路搜索树(B-Tree)索引,就可以加速数据的取回速度, Elasticsearch 以及 Lucene 使用的是一个叫做 反向索引(inverted index) 的结构来实现相同的功能。

    通常,每个文档中的字段都被创建了索引(拥有一个反向索引),因此他们可以被搜索。如果一个字段缺失了反向索引的话,它将不能被搜索。我们将会在之后的《反向索引》章节中详细介绍它。


    所以为了创建员工名单,我们需要进行如下操作:

      • 为每一个员工的 文档 创建索引,每个 文档 都包含了一个员工的所有信息。
      • 每个文档都会被标记为 employee 类型
      • 这种类型将存活在 megacorp 这个 索引 中。
      • 这个索引将会存储在 Elasticsearch 的集群中

    在实际的操作中,这些操作是非常简单的(即使看起来有这么多步骤)。我们可以把如此之多的操作通过一个命令来完成:

    PUT /megacorp/employee/1
    {
        "first_name" : "John",
        "last_name" :  "Smith",
        "age" :        25,
        "about" :      "I love to go rock climbing",
        "interests": [ "sports", "music" ]
    }
    

    注意在 /megacorp/employee/1 路径下,包含了三个部分:

    名字内容
    megacorp 索引的名字
    employee 类型的名字
    1 当前员工的ID

    请求部分,也就是 JSON 文档,在这里包含了关于这名员工的所有信息。他的名字是 “John Smith”,他已经25岁了,他很喜欢攀岩。

    怎么样?很简单吧!我们在操作前不需要进行任何管理操作,比如创建索引,或者为字段指定数据的类型。我们就这么直接地为一个文档创建了索引。Elasticsearch 会在创建的时候为它们设定默认值,所以所有管理操作已经在后台被默默地完成了。

    在进行下一步之前,我们再为这个目录添加更多的员工信息吧:

    PUT /megacorp/employee/2
    {
        "first_name" :  "Jane",
        "last_name" :   "Smith",
        "age" :         32,
        "about" :       "I like to collect rock albums",
        "interests":  [ "music" ]
    }
    
    PUT /megacorp/employee/3
    {
        "first_name" :  "Douglas",
        "last_name" :   "Fir",
        "age" :         35,
        "about":        "I like to build cabinets",
        "interests":  [ "forestry" ]
    }

    1.6 搜索

    检索文档

    现在,我们已经在 Elasticsearch 中存储了一些数据,我们可以开始根据这个项目的需求进行工作了。第一个需求就是要能搜索每一个员工的数据。

    对于 Elasticsearch 来说,这是非常简单的。我们只需要执行一次 HTTP GET 请求,然后指出文档的地址,也就是索引、类型以及 ID 即可。通过这三个部分,我们就可以得到原始的 JSON 文档:

    GET /megacorp/employee/1
    

    返回的内容包含了这个文档的元数据信息,而 John Smith 的原始 JSON 文档也在 _source 字段中出现了:

    {
      "_index" :   "megacorp",
      "_type" :    "employee",
      "_id" :      "1",
      "_version" : 1,
      "found" :    true,
      "_source" :  {
          "first_name" :  "John",
          "last_name" :   "Smith",
          "age" :         25,
          "about" :       "I love to go rock climbing",
          "interests":  [ "sports", "music" ]
      }
    }
    

    我们通过将HTTP后的请求方式由 PUT 改变为 GET 来获取文档,同理,我们也可以将其更换为 DELETE 来删除这个文档,HEAD 是用来查询这个文档是否存在的。如果你想替换一个已经存在的文档,你只需要使用 PUT再次发出请求即可。


    简易搜索

    GET 命令真的相当简单,你只需要告诉它你要什么即可。接下来,我们来试一下稍微复杂一点的搜索。

    我们首先要完成一个最简单的搜索命令来搜索全部员工:

    GET /megacorp/employee/_search
    

    你可以发现我们正在使用 megacorp 索引,employee 类型,但是我们我们并没有指定文档的ID,我们现在使用的是 _search 端口。你可以再返回的 hits 中发现我们录入的三个文档。搜索会默认返回最前的10个数值。

    {
       "took":      6,
       "timed_out": false,
       "_shards": { ... },
       "hits": {
          "total":      3,
          "max_score":  1,
          "hits": [
             {
                "_index":         "megacorp",
                "_type":          "employee",
                "_id":            "3",
                "_score":         1,
                "_source": {
                   "first_name":  "Douglas",
                   "last_name":   "Fir",
                   "age":         35,
                   "about":       "I like to build cabinets",
                   "interests": [ "forestry" ]
                }
             },
             {
                "_index":         "megacorp",
                "_type":          "employee",
                "_id":            "1",
                "_score":         1,
                "_source": {
                   "first_name":  "John",
                   "last_name":   "Smith",
                   "age":         25,
                   "about":       "I love to go rock climbing",
                   "interests": [ "sports", "music" ]
                }
             },
             {
                "_index":         "megacorp",
                "_type":          "employee",
                "_id":            "2",
                "_score":         1,
                "_source": {
                   "first_name":  "Jane",
                   "last_name":   "Smith",
                   "age":         32,
                   "about":       "I like to collect rock albums",
                   "interests": [ "music" ]
                }
             }
          ]
       }
    }
    

    注意:反馈值中不仅会告诉你匹配到哪些文档,同时也会把这个文档都会包含到其中:我们需要搜索的用户的所有信息。

    接下来,我们将要尝试着实现搜索一下哪些员工的姓氏中包含 Smith。为了实现这个,我们需要使用一种轻量的搜索方法。这种方法经常被称做 查询字符串(query string) 搜索,因为我们通过URL来传递查询的关键字:

    GET /megacorp/employee/_search?q=last_name:Smith
    

    我们依旧使用 _search 端口,然后可以将参数传入给 q=。这样我们就可以得到姓Smith的结果:

    {
       ...
       "hits": {
          "total":      2,
          "max_score":  0.30685282,
          "hits": [
             {
                ...
                "_source": {
                   "first_name":  "John",
                   "last_name":   "Smith",
                   "age":         25,
                   "about":       "I love to go rock climbing",
                   "interests": [ "sports", "music" ]
                }
             },
             {
                ...
                "_source": {
                   "first_name":  "Jane",
                   "last_name":   "Smith",
                   "age":         32,
                   "about":       "I like to collect rock albums",
                   "interests": [ "music" ]
                }
             }
          ]
       }
    }
    

    使用Query DSL搜索

    查询字符串是通过命令语句完成 点对点(ad hoc) 的搜索,但是这也有它的局限性(可参阅《搜索局限性》章节)。Elasticsearch 提供了更加丰富灵活的查询语言,它被称作 Query DSL,通过它你可以完成更加复杂、强大的搜索任务。

    DSL (Domain Specific Language 领域特定语言) 需要使用 JSON 作为主体,我们还可以这样查询姓 Smith 的员工:

    GET /megacorp/employee/_search
    {
        "query" : {
            "match" : {
                "last_name" : "Smith"
            }
        }
    }
    

    这个请求会返回同样的结果。你会发现我们在这里没有使用 查询字符串,而是使用了一个由 JSON 构成的请求体,其中使用了 match 查询法,随后我们还将会学习到其他的查询类型。

    更加复杂的搜索

    接下来,我们再提高一点儿搜索的难度。我们依旧要寻找出姓 Smith 的员工,但是我们还将添加一个年龄大于30岁的限定条件。我们的查询语句将会有一些细微的调整来以识别结构化搜索的限定条件 filter(过滤器):

    GET /megacorp/employee/_search
    {
        "query" : {
            "filtered" : {
                "filter" : {
                    "range" : {
                        "age" : { "gt" : 30 } <1>
                    }
                },
                "query" : {
                    "match" : {
                        "last_name" : "Smith" <2>
                    }
                }
            }
        }
    }
    
      1. 这一部分的语句是 range filter ,它可以查询所有超过30岁的数据 -- gt 代表 greater than (大于)

      2. 这一部分我们前一个操作的 match query 是一样的

    先不要被这么多的语句吓到,我们将会在之后带你逐渐了解他们的用法。你现在只需要知道我们添加了一个filter,可以在 match 的搜索基础上再来实现区间搜索。现在,我们的只会显示32岁的名为Jane Smith的员工了:

    {
       ...
       "hits": {
          "total":      1,
          "max_score":  0.30685282,
          "hits": [
             {
                ...
                "_source": {
                   "first_name":  "Jane",
                   "last_name":   "Smith",
                   "age":         32,
                   "about":       "I like to collect rock albums",
                   "interests": [ "music" ]
                }
             }
          ]
       }
    }
    

    全文搜索

    上面的搜索都很简单:名字搜索、通过年龄过滤。接下来我们来学习一下更加复杂的搜索,全文搜索——一项在传统数据库很难实现的功能。 我们将会搜索所有喜欢 rock climbing 的员工:

    GET /megacorp/employee/_search
    {
        "query" : {
            "match" : {
                "about" : "rock climbing"
            }
        }
    }
    

    你会发现我们同样使用了 match 查询来搜索 about 字段中的 rock climbing。我们会得到两个匹配的文档:

    {
       ...
       "hits": {
          "total":      2,
          "max_score":  0.16273327,
          "hits": [
             {
                ...
                "_score":         0.16273327, <1>
                "_source": {
                   "first_name":  "John",
                   "last_name":   "Smith",
                   "age":         25,
                   "about":       "I love to go rock climbing",
                   "interests": [ "sports", "music" ]
                }
             },
             {
                ...
                "_score":         0.016878016, <1>
                "_source": {
                   "first_name":  "Jane",
                   "last_name":   "Smith",
                   "age":         32,
                   "about":       "I like to collect rock albums",
                   "interests": [ "music" ]
                }
             }
          ]
       }
    }
    
      1. 相关评分

    通常情况下,Elasticsearch 会通过相关性来排列顺序,第一个结果中,John Smith 的 about 字段中明确地写到 rock climbing。而在 Jane Smith 的 about 字段中,提及到了 rock,但是并没有提及到 climbing,所以后者的 _score 就要比前者的低。

    这个例子很好地解释了 Elasticsearch 是如何执行全文搜索的。对于 Elasticsearch 来说,相关性的概念是很重要的,而这也是它与传统数据库在返回匹配数据时最大的不同之处。

    段落搜索

    能够找出每个字段中的独立单词固然很好,但是有的时候你可能还需要去匹配精确的短语或者 段落。例如,我们只需要查询到 about 字段只包含 rock climbing 的短语的员工。

    为了实现这个效果,我们将对 match 查询变为 match_phrase 查询:

    GET /megacorp/employee/_search
    {
        "query" : {
            "match_phrase" : {
                "about" : "rock climbing"
            }
        }
    }
    

    这样,系统会没有异议地返回 John Smith 的文档:

    {
       ...
       "hits": {
          "total":      1,
          "max_score":  0.23013961,
          "hits": [
             {
                ...
                "_score":         0.23013961,
                "_source": {
                   "first_name":  "John",
                   "last_name":   "Smith",
                   "age":         25,
                   "about":       "I love to go rock climbing",
                   "interests": [ "sports", "music" ]
                }
             }
          ]
       }
    }
    

    高亮我们的搜索

    很多程序希望能在搜索结果中 高亮 匹配到的关键字来告诉用户这个文档是 如何 匹配他们的搜索的。在 Elasticsearch 中找到高亮片段是非常容易的。

    让我们回到之前的查询,但是添加一个 highlight 参数:

    GET /megacorp/employee/_search
    {
        "query" : {
            "match_phrase" : {
                "about" : "rock climbing"
            }
        },
        "highlight": {
            "fields" : {
                "about" : {}
            }
        }
    }
    

    当我们运行这个查询后,相同的命中结果会被返回,但是我们会得到一个新的名叫 highlight 的部分。在这里包含了 about 字段中的匹配单词,并且会被 <em></em> HTML字符包裹住:

    {
       ...
       "hits": {
          "total":      1,
          "max_score":  0.23013961,
          "hits": [
             {
                ...
                "_score":         0.23013961,
                "_source": {
                   "first_name":  "John",
                   "last_name":   "Smith",
                   "age":         25,
                   "about":       "I love to go rock climbing",
                   "interests": [ "sports", "music" ]
                },
                "highlight": {
                   "about": [
                      "I love to go <em>rock</em> <em>climbing</em>" <1>
                   ]
                }
             }
          ]
       }
    }
    
      1. 在原有文本中高亮关键字。

    1.7 汇总

    统计

    最后,我们还有一个需求需要完成:可以让老板在职工目录中进行统计。Elasticsearch 把这项功能称作 汇总 (aggregations),通过这个功能,我们可以针对你的数据进行复杂的统计。这个功能有些类似于 SQL 中的GROUP BY,但是要比它更加强大。

    例如,让我们找一下员工中最受欢迎的兴趣是什么:

    GET /megacorp/employee/_search
    {
      "aggs": {
        "all_interests": {
          "terms": { "field": "interests" }
        }
      }
    }
    

    请忽略语法,让我们先来看一下结果:

    {
       ...
       "hits": { ... },
       "aggregations": {
          "all_interests": {
             "buckets": [
                {
                   "key":       "music",
                   "doc_count": 2
                },
                {
                   "key":       "forestry",
                   "doc_count": 1
                },
                {
                   "key":       "sports",
                   "doc_count": 1
                }
             ]
          }
       }
    }
    

    我们可以发现有两个员工喜欢音乐,还有一个喜欢森林,还有一个喜欢运动。这些数据并没有被预先计算好,它们是在文档被查询的同时实时计算得出的。如果你想要查询姓 Smith 的员工的兴趣汇总情况,你就可以执行如下查询:

    GET /megacorp/employee/_search
    {
      "query": {
        "match": {
          "last_name": "smith"
        }
      },
      "aggs": {
        "all_interests": {
          "terms": {
            "field": "interests"
          }
        }
      }
    }
    

    这样,all_interests 的统计结果就只会包含满足查询的文档了:

      ...
      "all_interests": {
         "buckets": [
            {
               "key": "music",
               "doc_count": 2
            },
            {
               "key": "sports",
               "doc_count": 1
            }
         ]
      }
    

    汇总还允许多个层面的统计。比如我们还可以统计每一个兴趣下的平均年龄:

    GET /megacorp/employee/_search
    {
        "aggs" : {
            "all_interests" : {
                "terms" : { "field" : "interests" },
                "aggs" : {
                    "avg_age" : {
                        "avg" : { "field" : "age" }
                    }
                }
            }
        }
    }
    

    虽然这次返回的汇总结果变得更加复杂了,但是它依旧很容易理解:

      ...
      "all_interests": {
         "buckets": [
            {
               "key": "music",
               "doc_count": 2,
               "avg_age": {
                  "value": 28.5
               }
            },
            {
               "key": "forestry",
               "doc_count": 1,
               "avg_age": {
                  "value": 35
               }
            },
            {
               "key": "sports",
               "doc_count": 1,
               "avg_age": {
                  "value": 25
               }
            }
         ]
      }
    

    在这个丰富的结果中,我们不但可以看到兴趣的统计数据,还能针对不同的兴趣来分析喜欢这个兴趣的平均年龄

    即使你现在还不能很好地理解语法,但是相信你还是能发现,用这个功能来实现如此复杂的统计工作是这样的简单。你的极限取决于你存入了什么样的数据哟!

    1.8 小结 

    希望上面的几个小教程可以很好地向你解释 Elasticsearch 可以实现什么功能。为了保持教程简短,这里只提及了一些基础,除此之外还有很多功能,比如建议、地理定位、过滤、模糊以及部分匹配等。但是相信你也发现了,在这里你只需要很简单的操作就可以完成复杂的操作。无需配置,添加数据就可以开始搜索!

    可能前面有一些语法会让你觉得很难理解,你可能对如何调整优化它们还有很多疑问。那么,本书之后的章节将会帮助你逐步解开疑问,让你对 Elasticsearch 是如何工作的有一个全面的了解。

    1.9 分布式

    分布式特性

    在最开始的章节中,我们曾经提到 Elasticsearch 可以被扩展到上百台(甚至上千台)服务器上,来处理PB级别的数据。我们的教程只提及了如何使用它,但是并没有提及到服务器方面的内容。Elasticsearch 是自动分布的,它在设计时就考虑到可以隐藏分布操作的复杂性。

    Elasticsearch 的分布式部分很简单。你甚至不需要关于分布式系统的任何内容,比如分片、集群、发现等成堆的分布式概念。你可能在你的笔记本中运行着刚才的教程,如果你想在一个拥有100个节点的集群中运行教程,你会发现操作是完全一样的。

    Elasticsearch 很努力地在避免复杂的分布式系统,很多操作都是自动完成的:

      • 可以将你的文档分区到不同容器或者 分片 中,这些文档可能被存在一个节点或者多个节点。
      • 跨节点平衡集群中节点间的索引与搜索负载。
      • 自动复制你的数据以提供冗余副本,防止硬件错误导致数据丢失。
      • 自动在节点之间路由,以帮助你找到你想要的数据。
      • 无缝扩展或者恢复你的集群。

    当你在阅读这本书时,你会发现到有关 Elasticsearch 的分布式特性分布式特性的补充章节。在这些章节中你会了解到如何扩展集群以及故障转移(《分布式集群》),如何处理文档存储(《分布式文档》),如何执行分布式搜索(《分布式搜索》)

    这一部分不是必须要看的——你不懂它们也能正常使用 Elasticsearch。但是帮助你更加全面完整地了解 Elasticsearch。你也可以在之后需要的时候再回来翻阅它们。

    1.10 本章总结

    到目前为止,你应该已经知道 Elasticsearch 可以实现哪些功能,入门上手是非常简单的。只需要最少的知识和配置就可以开始使用 Elasticsearch 也是它的追求。学习 Elasticsearch 最好的方法就是开始使用它:进行的检索与搜索吧!

    当然,学得越多,你的生产力就越高。你也就能对特定的内容进行微调,得到更适合你的结果。

    之后的章节,我们将会引领你从新手晋级到专家。每一个章节都会解释一个要点,同时我们也会提供专家级别的小提示。如果你只是刚刚起步,这些提示可能并不是很适合你。Elasticsearch 会在一开始设置很多合理的默认值。你可以在需要提升性能的时候再重新回顾它们。

  • 相关阅读:
    Spring MVC(1)Spring MVC的初始化和流程以及SSM的实现
    Spring(四)Spring与数据库编程
    MyBatis(4)-- 动态SQL
    MyBatis(3)-- Mapper映射器
    MyBatis(2)-- MyBatis配置mybatis-config.xml
    MyBatis(1)-- MyBatis介绍
    计算机网络(2)-- URL、HTTP、HTTPS、HTML
    计算机网络(1)- TCP
    Shell脚本编程
    和为定值的多个数
  • 原文地址:https://www.cnblogs.com/Wolfmanlq/p/5984376.html
Copyright © 2020-2023  润新知