Elasticsearch 入门使用

Elasticsearch 是一款稳定高效的分布式搜索和分析引擎,它的底层基于 Lucene,并提供了友好的 RESTful API 来对数据进行操做,还有比较重要的一点是, Elasticsearch 开箱便可用,上手也比较容易。javascript

目前 Elasticsearch 在搭建企业级搜索(如日志搜索、商品搜索等)平台中很普遍,官网也提供了很多案例,好比:html

  • GitHub 使用 Elasticsearch 检索超过 800 万的代码库
  • eBay 使用 Elasticsearch 搜索海量的商品数据
  • Netflix 使用 Elasticsearch 来实现高效的消息传递系统

本文主要介绍 Elasticsearch 的基本概念及入门使用。java

安装

在安装 Elasticsearch 以前,请确保你的计算机已经安装了 Java。目前 Elasticsearch 的最新版是 5.2,须要安装 Java 8,若是你用的是老版本的 Elasticsearch,如 2.x 版,可用 Java 7,但仍是推荐使用 Java 8。node

可使用以下的命令检查 Java 的版本:git

$ java -version复制代码

接着,咱们能够从这里下载最新版本的 Elasticsearch,也可以使用 wget 下载,以下:数据库

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.2.tar.gz复制代码

Windows 用户也能够下载 .zip 格式的安装包。apache

下载完后进行解压:json

$ tar -zxvf elasticsearch-5.2.2.tar.gz复制代码

运行

首先,咱们进入到刚刚解压出来的目录中:数组

$ cd elasticsearch-5.2.2复制代码

接着,使用以下命令启动 Elasticsearch:浏览器

$ bin/elasticsearch复制代码

此时,若是正常的话,你能够在终端看到相似以下的输出:

[2017-03-04T23:25:09,961][INFO ][o.e.n.Node               ] [] initializing ...
[2017-03-04T23:25:10,073][INFO ][o.e.e.NodeEnvironment    ] [yO11WLM] using [1] data paths, mounts [[/ (/dev/disk0s2)]], net usable_space [141.1gb], net total_space [232.9gb], spins? [unknown], types [hfs]
[2017-03-04T23:25:10,074][INFO ][o.e.e.NodeEnvironment    ] [yO11WLM] heap size [1.9gb], compressed ordinary object pointers [true]
[2017-03-04T23:25:10,095][INFO ][o.e.n.Node               ] node name [yO11WLM] derived from node ID [yO11WLMOQDuAOpZbYZYjzw]; set [node.name] to override
[2017-03-04T23:25:10,100][INFO ][o.e.n.Node               ] version[5.2.2], pid[7607], build[db0d481/2017-02-09T22:05:32.386Z], OS[Mac OS X/10.11.5/x86_64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_102/25.102-b14]
[2017-03-04T23:25:11,363][INFO ][o.e.p.PluginsService     ] [yO11WLM] loaded module [aggs-matrix-stats]
...复制代码

上面的命令是在前台运行的,若是想在后台以守护进程模式运行,能够加 -d 参数。

Elasticsearch 启动后,也启动了两个端口 9200 和 9300:

  • 9200 端口:HTTP RESTful 接口的通信端口
  • 9300 端口:TCP 通信端口,用于集群间节点通讯和与 Java 客户端通讯的端口

如今,让咱们作一些测试。在浏览器访问连接 http://localhost:9200/ ,或使用 curl 命令:

$ curl 'http://localhost:9200/?pretty'复制代码

咱们能够看到相似以下的输出:

{
  "name" : "yO11WLM",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "yC8BGwzlSnu_zGbKL918Xg",
  "version" : {
    "number" : "5.2.1",
    "build_hash" : "db0d481",
    "build_date" : "2017-02-09T22:05:32.386Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.1"
  },
  "tagline" : "You Know, for Search"
}复制代码

概念

在进一步使用 Elasticsearch 以前,让咱们先了解几个关键概念。

在逻辑层面:

  • Index (索引):这里的 Index 是名词,一个 Index 就像是传统关系数据库的 Database,它是 Elasticsearch 用来存储数据的逻辑区域
  • Document (文档):Elasticsearch 使用 JSON 文档来表示一个对象,就像是关系数据库中一个 Table 中的一行数据
  • Type (类型):文档归属于一种 Type,就像是关系数据库中的一个 Table
  • Field (字段):每一个文档包含多个字段,相似关系数据库中一个 Table 的列

咱们用一个表格来作类比,以下:

Elasticsearch MySQL
Index Database
Type Table
Document Row
Field Column

在物理层面:

  • Node (节点):node 是一个运行着的 Elasticsearch 实例,一个 node 就是一个单独的 server
  • Cluster (集群):cluster 是多个 node 的集合
  • Shard (分片):数据分片,一个 index 可能会存在于多个 shard

使用

接下来,咱们看看如何创建索引、建立文档等,就比如在 MySQL 中进行诸如建立数据库,插入数据等操做。

添加文档

下面,咱们将建立一个存储电影信息的 Document:

  • Index 的名称为 movie
  • Type 为 adventure
  • Document 有两个字段:name 和 actors

咱们使用 Elasticsearch 提供的 RESTful API 来执行上述操做,如图所示:

  • 用 url 表示一个资源,好比 /movie/adventure/1 就表示一个 index 为 movie,type 为 adventure,id 为 1 的 document
  • 用 http 方法操做资源,如使用 GET 获取资源,使用 POST、PUT 新增或更新资源,使用 DELETE 删除资源等

咱们可使用 curl 命令来执行上述操做:

$ curl -i -X PUT "localhost:9200/movie/adventure/1" -d '{"name": "Life of Pi", "actors": ["Suraj", "Irrfan"]}'复制代码

不过,本文推荐使用 httpie,相似 curl,但比 curl 更好用,将上面的命令换成 httpie,以下:

$ http put :9200/movie/adventure/1 name="Life of Pi" actors:='["Suraj", "Irrfan"]'复制代码

上面的命令结果以下:

HTTP/1.1 201 Created
Location: /movie/adventure/1
content-encoding: gzip
content-type: application/json; charset=UTF-8
transfer-encoding: chunked

{
    "_id": "1",
    "_index": "movie",
    "_shards": {
        "failed": 0,
        "successful": 1,
        "total": 2
    },
    "_type": "adventure",
    "_version": 1,
    "created": true,
    "result": "created"
}复制代码

能够看到,咱们已经成功建立了一个 _index 为 movie,_type 为 adventure,_id 为 1 的文档。

咱们经过 GET 请求来查看这个文档的信息:

$ http :9200/movie/adventure/1复制代码

结果以下:

HTTP/1.1 200 OK
content-encoding: gzip
content-type: application/json; charset=UTF-8
transfer-encoding: chunked

{
    "_id": "1",
    "_index": "movie",
    "_source": {
        "actors": [
            "Suraj",
            "Irrfan"
        ],
        "name": "Life of Pi"
    },
    "_type": "adventure",
    "_version": 1,
    "found": true
}复制代码

能够看到,原始的文档数据存在了 _source 字段中。

若是咱们的数据没有 id,也可让 Elasticsearch 自动为咱们生成,此时要使用 POST 请求,形式以下:

POST /movie/adventure/
{
    "name": "Life of Pi"
}复制代码

更新整个文档

当咱们使用 PUT 方法指明文档的 _index, _type_id时,若是 _id 已存在,则新文档会替换旧文档,此时文档的 _version 会增长 1,而且 _created 字段为 false。好比:

$ http put :9200/movie/adventure/1 name="Life of Pi"复制代码

结果以下:

HTTP/1.1 200 OK
content-encoding: gzip
content-type: application/json; charset=UTF-8
transfer-encoding: chunked

{
    "_id": "1",
    "_index": "movie",
    "_shards": {
        "failed": 0,
        "successful": 1,
        "total": 2
    },
    "_type": "adventure",
    "_version": 2,
    "created": false,
    "result": "updated"
}复制代码

使用 GET 请求查看新文档的数据:

$ http :9200/movie/adventure/1复制代码

结果以下:

HTTP/1.1 200 OK
content-encoding: gzip
content-type: application/json; charset=UTF-8
transfer-encoding: chunked

{
    "_id": "1",
    "_index": "movie",
    "_source": {
        "name": "Life of Pi"
    },
    "_type": "adventure",
    "_version": 2,
    "found": true
}复制代码

能够看到,actors 这个字段已经不存在了,文档的 _version 变成了 2。

所以,为了不在误操做的状况下,原文档被替换,咱们可使用 _create 这个 API,表示只在文档不存在的状况下才建立新文档(返回 201 Created),若是文档存在则不作任何操做(返回 409 Conflict),命令以下:

$ http put :9200/movie/adventure/1/_create name="Life of Pi"复制代码

因为文档 id 存在,会返回 409 Conflict。

局部更新

在有些状况下,咱们只想更新文档的局部,而不是整个文档,这时咱们可使用 _update 这个 API。

如今,待更新的文档信息以下:

{
    "_id": "1",
    "_index": "movie",
    "_source": {
        "name": "Life of Pi"
    },
    "_type": "adventure",
    "_version": 2,
    "found": true
}复制代码

最简单的 update 请求接受一个局部文档参数 doc,它会合并到现有文档中:将对象合并在一块儿,存在的标量字段被覆盖,新字段被添加。

形式以下:

POST /movie/adventure/1/_update
{
   "doc": {
      "name": "life of pi"
   }
}复制代码

因为有嵌套字段,咱们能够这样使用 http(这里须要注意使用 POST 方法):

$ echo '{"doc": {"actors": ["Suraj", "Irrfan"]}}' | http post :9200/movie/adventure/1/_update复制代码

上面的命令中,咱们添加了一个新的字段:actors,结果以下:

HTTP/1.1 200 OK
content-encoding: gzip
content-type: application/json; charset=UTF-8
transfer-encoding: chunked

{
    "_id": "1",
    "_index": "movie",
    "_shards": {
        "failed": 0,
        "successful": 1,
        "total": 2
    },
    "_type": "adventure",
    "_version": 3,
    "result": "updated"
}复制代码

能够看到,_version 增长了 1,result 的结果是 updated。

检索文档

检索某个文档

要检索某个文档很简单,咱们只需使用 GET 请求并指出文档的 index, type, id 就能够了,好比:

$ http :9200/movie/adventure/1/复制代码

响应内容会包含文档的元信息,文档的原始数据存在 _source 字段中。

咱们也能够直接检索出文档的 _source 字段,以下:

$ http :9200/movie/adventure/1/_source复制代码

检索全部文档

咱们可使用 _search 这个 API 检索出全部的文档,命令以下:

$ http :9200/movie/adventure/_search复制代码

返回结果以下:

{
    "_shards": {
        "failed": 0,
        "successful": 5,
        "total": 5
    },
    "hits": {
        "hits": [
            {
                "_id": "1",
                "_index": "movie",
                "_score": 1.0,
                "_source": {
                    "actors": [
                        "Suraj",
                        "Irrfan"
                    ],
                    "name": "Life of Pi"
                },
                "_type": "adventure"
            }
        ],
        "max_score": 1.0,
        "total": 1
    },
    "timed_out": false,
    "took": 299
}复制代码

能够看到,hits 这个 object 包含了 hits 数组,total 等字段,其中,hits 数组包含了全部的文档,这里只有一个文档,total 代表了文档的数量,默认状况下会返回前 10 个结果。咱们也能够设定 From/Size 参数来获取某一范围的文档,可参考这里,好比:

$ http :9200/movie/adventure/_search?from=1&size=5复制代码

当不指定 from 和 size 时,会使用默认值,其中 from 的默认值是 0,size 的默认值是 10。

检索某些字段

有时候,咱们只需检索文档的个别字段,这时可使用 _source 参数,多个字段可使用逗号分隔,以下所示:

$ http :9200/movie/adventure/1?_source=name
$ http :9200/movie/adventure/1?_source=name,actors复制代码

query string 搜索

query string 搜索以 q=field:value 的形式进行查询,好比查询 name 字段含有 life 的电影:

$ http :9200/movie/adventure/_search?q=name:life复制代码

DSL 搜索

上面的 query string 搜索比较轻量级,只适用于简单的场合。Elasticsearch 提供了更为强大的 DSL(Domain Specific Language)查询语言,适用于复杂的搜索场景,好比全文搜索。咱们能够将上面的 query string 搜索转换为 DSL 搜索,以下:

GET /movie/adventure/_search
{
    "query" : {
        "match" : {
            "name" : "life"
        }
    }
}复制代码

若是使用 httpie,能够这样:

$ echo '{"query": {"match": {"name": "life"}}}' | http get :9200/movie/adventure/_search复制代码

若是使用 curl,能够这样:

$ curl -X GET "127.0.0.1:9200/movie/adventure/_search" -d '{"query": {"match": {"name": "life"}}}'复制代码

文档是否存在

使用 HEAD 方法查看文档是否存在:

$ http head :9200/movie/adventure/1复制代码

若是文档存在则返回 200,不然返回 404。

删除文档

使用 DELETE 方法删除文档:

$ http delete :9200/movie/adventure/1复制代码

小结

  • Elasticsearch 经过简单的 RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单
  • 在建立文档时,咱们能够用 POST 方法指定将文档添加到某个 _index/_type 下,来让 Elasticsearch自动生成惟一的 _id;而用 PUT 方法指定将文档的 _index/_type/_id

本文由 funhacks 发表于我的博客,采用 Creative Commons BY-NC-ND 4.0(自由转载-保持署名-非商用-禁止演绎)协议发布。
非商业转载请注明做者及出处。商业转载请联系做者本人。
本文标题为: Elasticsearch 入门使用
本文连接为: funhacks.net/2017/03/22/…

参考资料

相关文章
相关标签/搜索