• Elasticsearch


    Elasticsearch是基于Apache 2.0开源的实时、分布式、分析搜索引擎,相比Lucene,Elasticsearch的上手比较容易,这篇文章主要纪录Elasticsearch的基本概念和基本API。

    官方对Elasticsearch的定义:

    Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the unexpected.


    你可能已经在Elasticsearch的文档中看过如下词汇:

    • NRT: 近实时(Near Realtime),当一个文档保存至index,短暂的延迟后就可以被搜索。
    • Node: 指单个实例,存储文档并参与所在集群的索引和搜索,一台机器可以运行多个实例,每个实例启动时都有自己的唯一标识。
    • Cluster: 指多个实例组成的集群,集群中的节点有相同的cluster.name(默认为"elasticsearch"),用户可以通过集群对多个节点的所有数据进行索引和搜索。
    • Index: 索引在Elasticsearch中有两种含义。作为名词,索引可以指文档的集合,作为动词,可以说"对某个文档进行索引",也就是把文档存储到索引。一个index的名称即为其标识,名称必须为小写。如果和RDBMS相比的话,index的概念可能和database比较相似。
    • Type: 用于对同一个index中的数据进行逻辑分类。例如,有个存储了sns数据的index,这个index中可能存在多个类型,例如用户资料数据、评论数据、聊天数据...
    • Document: 文档以JSON格式存储,文档中包含多个字段,每个文档都有自己的类型并存储于index中。
    • Shards: index可以切分成多个shard,每个shard分布到不同的节点上。通过shard可以在存储还是搜索上缓解单个节点的压力。
    • Replicas: 对shard进行复制,通过副本不仅保证了可用性,也提高了搜索效率。

    一个index可以分为多个shard,默认配置下,每个index有5个primary shards和1个副本(也就是5个replica shards),也就是说这个index有10个shards。


    为了进一步说明,这里简单说明一下安装过程。
    首先需要确认机器上是否已经安装了Java,这里建议使用java 8:

    java -version
    echo $JAVA_HOME


    根据自己需要,可以选择使用apt-getyum进行安装,或者直接运行docker容器(docker.elastic.co/elasticsearch/elasticsearch:5.3.1), 参考https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html
    这里我们用TAR包进行安装

    cd
    wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.1.tar.gz
    cp elasticsearch-5.2.1.tar.gz /usr/local ; cd $_
    tar xzvf elasticsearch-5.2.1.tar.gz


    启动时可以指定集群名称和节点名称:

    elasticsearch-5.2.1/bin/elasticsearch -Ecluster.name=cluster0 -Enode.name=node0


    Elasticsearch的web接口的默认端口为9200,或者可以根据自己的情况,在bin/elasticsearch.yml中对http.port进行修改。
    最后查看响应结果,参考:

    $ curl http://localhost:9200/
    {
      "name" : "F16Po5W",
      "cluster_name" : "elasticsearch",
      "cluster_uuid" : "gDEP8ViaSVuQkCADjMkWHg",
      "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"
    }


    下面检查一下集群的状态,参考:

    $ curl http://localhost:9200/_cat/health?v
    epoch      timestamp cluster  status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
    1488018007 12:00:00  cluster0 green           1         1      0   0    0    0        0             0                  -                100.0%

    输出显示,名为"elasticsearch"的状态为"green",状态分三种,green(健康)、yellow(服务可用,尚未分配副本)、red(不可用)。
    red也并不是完全不可用,部分功能还是可以用的,例如搜索请求还是可以在部分shards中进行。

    上面用到的_cat API,可以参考https://www.elastic.co/guide/en/elasticsearch/reference/current/cat.html,参数v代表verbose。

    如果需要JSON格式,则去掉_cat即可,参考:

    curl http://localhost:9200/_cluster/health?pretty


    health只反映集群的大体情况,更详细的信息,比如版本、节点、metadata等可以通过state获得:

    curl http://localhost:9200/_cluster/state?pretty


    另外,还有一个stats,和state不同的是,stats返回的是和性能相关的信息,比如各项字节数、OS、fs、jvm等。
    类似地,检查节点状态:

    $ curl http://localhost:9200/_cat/nodes?v
    ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
    127.0.0.1            7          90   5    0.00    0.01     0.05 mdi       *      node0


    由于启动时指定了节点名称,这里节点的名称为node0。
    检查index状态:

    $ curl http://localhost:9200/_cat/indices?v
    health status index uuid pri rep docs.count docs.deleted store.size pri.store.size


    注意不是index的复数为indices,由于尚未创建任何index,这里没有输出。
    但这并不妨碍试试analyze:

    curl -X POST http://localhost:9200/_analyze?pretty -d '{"analyzer" : "standard", "text" : "Kavlez.Kim@gmail.com"}'


    下面开始是Elasticsearch各个单位的基本API使用介绍。


    Index

    接下来创建一个index,注意不是POST,是PUT,参考:

    $ curl -X PUT http://localhost:9200/province?pretty
    {
      "acknowledged" : true,
      "shards_acknowledged" : true
    }


    重新确认下index状态:

    $ curl http://localhost:9200/_cat/indices?v
    health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
    yellow open   province Ks7940k5QYKp9t7AEntbBA   5   1          0            0       650b           650b


    如之前所说,默认有5个primary shards和1个replicas,尽管还没有任何文档。
    第一个字段,健康状态显示为yellow,这是因为尚未分配副本,而我们只有一个节点。

    创建index时也可以指定其他属性,比如:

    curl -X PUT -d '
    {
       "settings" : {
          "number_of_shards" : 3
       },
       "mappings" : {
          "type1" : {
             "_source" : { "enabled" : false }, "properties" : {
                "name" : { "type" : "string" }, "code" : {"type":"string"}
             }
          }
       },
       "aliases" : {
          "alias_1" : {
             "filter" : {
                "term" : {"subdivision" : "Municipality" }
             }
          }
       }
    }' http://localhost:9200/province 


    至于GET,不只是用于察看index:

    curl http://localhost:9200/province
    curl http://localhost:9200/province/_settings
    curl http://localhost:9200/province/_stats
    curl http://localhost:9200/province/_flush
    curl http://localhost:9200/province/_refresh

    删除一个index可以通过DELETE,如果并不打算删除index,但又希望无法访问该index,此时可以close
    可以通过POST /{index}/_close/{index}/_open对index进行开关,当用户访问已关闭的index时会提示错误。

    也可以通过_all或通配符对所有的index批量操作,但考虑到风险,可以通过在配置文件修改action.destructive_requires_name项禁用批量指定。

    已关闭的index也会消耗一定的磁盘空间,开关操作可以通过cluster.indices.close.enable项禁用,该项默认为true

    Document

    文档相关操作,先在province index中添加两个文档:

    $ curl -X PUT -d '{"name": "Hong Kong", "code": "CN-91", "native": "香港"}' http://localhost:9200/province/special/1?pretty
    {
      "_index" : "province",
      "_type" : "special",
      "_id" : "1",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "created" : true
    }
    
    $ curl -X PUT -d  '{"name": "Beijing", "code": "CN-11", "native": "北京"}' http://localhost:9200/province/municipality/1?pretty
    {
      "_index" : "province",
      "_type" : "municipality",
      "_id" : "1",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "created" : true
    }


    请求中的specialmunicipality指的就是文档的类型,尽管两个文档在同一个index,但类型不同。
    后面的1就是文档的id,可以对特定的index/type/id重新PUT,如果用同一个id提交多次,每次提交时_version会自动+1。
    如果希望指定操作类型,则加上op_type参数,例如下面的例子会触发versionconflictengine_exception,而不是version+1:

    curl -X PUT -d '{"name": "Hong Kong", "code": "CN-91", "native": "香港"}' http://localhost:9200/province/special/1?op_type=create


    如果希望添加文档时自动生成id,则使用POST,此时就不能指定op_type了。

    添加操作时不小心写错了index的名称,但还是成功了,列出indices(GET _cat/indices)发现有几个写错名称的index。
    Elasticsearch默认允许向不存在的index添加文档,不存在则自动创建,该设置可以通过action.autocreateindex项进行修改,比如:

    action.auto_create_index: +kav*,-da*

    允许名称以"kav"开头的index自动创建,禁止以"da"开头的。
    如果想全部禁止,则设置-*


    如果我想在已有的文档中添加字段,相比重新将整个文档重新PUT,不如用脚本进行更新,参考:

    $ curl -X POST http://localhost:9200/province/special/1/_update -d '
    {
       "script":{
          "inline": "ctx._source.dc = params.dial_code", "params":{
             "dial_code": 852
          }
       }
    }'
    {"_index":"province","_type":"special","_id":"1","_version":5,"result":"updated","_shards":{"total":2,"successful":1,"failed":0}}


    至于GET,基本用法如下:

    $ curl  http://10.69.201.47:9200/province/special/1?pretty
    {
      "_index" : "province",
      "_type" : "special",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "name" : "Hong Kong",
        "code" : "CN-91",
        "native" : "香港"
      }
    }


    另外,可以用_source进行过滤

    $ curl  http://localhost:9200/province/special/1/_source=name,code?pretty
    {
      "_index" : "province",
      "_type" : "special",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "name" : "Hong Kong",
        "code" : "CN-91"
      }
    }


    如果想一次请求多个文档,可以使用_mget,参考:

    curl -X POST http://localhost:9200/_mget -d '
    {
       "docs":[
          {
             "_index":"province", "_type": "special", "_id": "1"
          },
          {
             "_index":"province", "_type":"municipality", "_id": "1"
          }
       ]
    }'


    docs数组的第二项并不存在,于是返回{"_index" : "province", "_type" : "municipality", "_id" : "1", "found" : false }

    删除文档用DELETE方法,删除时可以加上其他参数,例如:

    $ curl -X delete  http://localhost:9200/province/special/1?version=1
    {
        "_index": "province",
        "_type": "special",
        "_id": "1",
        "_version": 1,
        "found": true,
        "_source": {
            "name": "Hong Kong",
            "code": "CN-91",
            "native": "香港"
        }
    }

    Search

    search API提供两种方式:

    • URI Search: GET的URL后面带上query string
    • Request Body Search: 也就是将Query DSL作为body请求


    至于搜索的对象,可以是多个index,也可以是某个index下的多个type。
    search API默认为跨多个index和type,搜索的范围需要在请求时指定。

    对多个index,比如

    curl http://localhost:9200/province,country/_search?q=name:Hong*

    对多个type,比如

    curl http://localhost:9200/province/special,municipality/_search?q=name:Shang*


    下面是GET搜索时用到的一些常见的参数

    NameDescription
    q 基本的query string,例如q=name:Hong*
    df 即default field
    analyzer 指定要使用的analyzer
    analyze_wildcard 是否对通配符进行分析,默认为false
    default_operator 可选值为AND和OR,默认为OR
    lenient true时忽略数据格式警告,默认为false
    _source 改项为false时结果将不包含文档内容, 也可以通过sourceinclude & sourceexclude对返回字段进行筛选(逗号分隔)
    stored_fields 对返回字段进行筛选(逗号分割)
    sort 指定排序策略,格式为 fieldName:asc/fieldName:desc
    timeout 超时时长
    from 响应结果起始索引,默认为0
    size 响应结果数,默认为10
    search_type 可以为dfsquerythenfetch或者querythen_fetch,默认为后者


    URL参数难以表述复杂的搜索,Elasticsearch提供了基于JSON格式的Query DSL来进行搜索。
    虽然Query DSL提供了丰富的查询类型,但就整体而言,提供不外乎两种:

    • leaf query: 例如match,term,range,也就是匹配特定字段的特定值
    • compound query: 将其它leaf聚合到一起或者多个查询聚合到一起。

    由于DSL相关的内容过多,这里只简单列举几种常用用法以作参考。

    • match all: match_all用于返回所有score为1.0内容

      $ curl -X post http://10.69.201.47:9200/province/_search -d '{
         "query":{
            "match_all":{}
         }
      }'
    • match: 根据字段和值的匹配进行搜索

      $ curl -X post http://10.69.201.47:9200/province/_search -d '{
         "query":{
            "match":{
                  "name":"Hong Kong"
            }
         }
      }'
    • multi match: 用多个字段进行匹配,比如下面的例子中"CN-91"是香港的code,而这里却用name和native字段进行搜索,因此没有结果

      curl -X post http://10.69.201.47:9200/province/_search -d '{
         "query":{
           "multi_match":{
                 "query":"CN-91",
                 "fields":["name","native"]
           }
         }
      }'
    • query string: 如果我想multi match所有字段呢? 可以用query string

      curl -X post http://10.69.201.47:9200/province/_search -d '
      {
         "query":{
            "query_string":{
               "query":"Hong"
            }
         }
      }'
    • term: term搜索属于低级(low-level)搜索,也就是直接查询倒排索引(inverted index),而不经过分析过程。 在倒排索引中不存在则无结果。 下面的例子中,用"Hong"来搜索是没有结果的,需要用"hong"

      curl -X post http://10.69.201.47:9200/province/_search -d '
      {
         "query":{
            "term":{"name":"hong"}
         }
      }
      '
    • range: 也属于term搜索的一种,根据比较来限制值的范围,支持的操作有gte,gt,lte,lt,例如

      curl -X POST http://10.69.201.47:9200/province/_search -d '{
         "query":{
            "range":{
               "code":{
                  "gt":100
               }
            }
         }
      }'
    • type: 搜索对应type的文档,属于term level,因此type要严格匹配,例如

      curl -X POST http://10.69.201.47:9200/province/_search -d '{
         "query":{
            "type":{
               "value":"special"
            }
         }
      }'
  • 相关阅读:
    如何构建微服务架构
    JVM内幕:Java虚拟机详解
    JVM 调优系列之图解垃圾回收
    干货:JVM 堆内存和非堆内存
    JavaWeb项目架构之NFS文件服务器
    SSH框架之-hibernate 三种状态的转换
    随笔聊架构
    如果不从事编程,我可以做什么?
    JAVA几种缓存技术介绍说明
    Java反射机制应用实践
  • 原文地址:https://www.cnblogs.com/kavlez/p/elasticsearch-tutorial.html
Copyright © 2020-2023  润新知