zoukankan      html  css  js  c++  java
  • ElasticSearch之一——索引

    ElasticSearch索引

    ElasticSearch 是一个分布式可扩展的实时搜索引擎,它建立在开源搜索引擎框架Apache Lucene基础上。
    ElasticSearch 不但包括了全文搜索功能,还支持一下特性:
    1、分布式实时文件存储,将每一个字段都编入索引,使其可以被搜索;
    2、实时分析的分布式搜索引擎;
    3、可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据;

    1、与ElasticSearch 通信

    Java API

    如果使用Java,ElasticSearch(简写ES) 内置了两个客户端:
    1、节点客户端:以一个无数据节点的身份加入一个集群,它自身没有数据,但它知道什么数据在集群的哪一个节点上,然后就可以将请求转发到正确的节点上。
    2、传输客户端:它本身并不加入集群,而用来向远程集群发送请求。

    这两个客户端都使用ElasticSearch的传输协议,通过9300端口与java客户端进行通信,集群中的每个节点也是通过9300端口进行通信。

    HTTP RESTful API

    其它非Java语言可以采用HTTP协议,通过9200端口与ES的RESTful API进行通信。

    向ES发出HTTP请求,例如请求集群中文件的数量:
    http://localhost:9200/_count?pretty

    ES返回一个json字符串:

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

    2、文档

    ES是面向文档型数据库,并为它们建立索引,这样我们可以在ES中索引、搜索、排序和过滤这些文档。

    ES使用JSON作为文档序列化的格式,例如:

    一个文档不只包含了数据。它还包含了元数据(metadata) —— 关于文档的信息。有三个元数据元素是必须存在的,它们是:

    名字说明
    _index 文档存储的地方
    _type 文档代表的对象种类
    _id 文档的唯一编号

    一篇文档通过 _index, _type以及_id来确定它的唯一性,下面对比了这几个名词与关系型数据库的关系:

    关系型数据库 数据库
    ElasticSearch 索引 类型 文档 字段

     

    一个ES集群可以包含多个索引(数据库),每个索引又包含了很多类型(表),类型中包含了很多文档(行),每个文档又包含了很多字段(列)。

    在ES中,索引有多重含义:
    1、索引(名词),一个索引就类似与传统关系型数据库中的数据库,这里就是存储相关文档的地方;
    2、索引(动词),把一个文档存储到一个索引中的过程,这样它才能被检索,这个过程类似于SQL中的INSERT命令;
    3、反向索引,通常每个文档中的字段都被创建了反向索引,如果一个字段没有反向索引,那么它将不能被搜索。

     

    下面演示通过HTTP请求如何建立索引:

    1、添加文档(PUT请求)

    curl "127.0.0.1:9200/sina/employee/11412" -d '{"name":"chenqi","age":30}'

    返回值:

    {"_index":"sina","_type":"employee","_id":"11412","_version":1,"created":true}

    sina是索引名,employee是类型名,11412是文档ID,它们组合构成了请求url的路径;

    注意:_version 字段表示文档的版本,每当文档发生变化时,_version就会增大。

    总结下添加文档的方法:

    PUT /{index}/{type}/{id}
    {
      "field": "value",
      ...
    }

    如果在请求中不指定id,ES会自动分配一个自增ID;

    如果指定的文档id在索引中已存在,则更新原文档,此时文档的_version会增加1,并且_created字段为false;

    如果只打算在文档不存在的情况下才创建新文档,则使用下面两种方法之一即可:

    PUT /{index}/{type}/{id}?op_type=create
    PUT /{index}/{type}/{id}/_create

    创建成功返回201 Created;如果文档ID已存在,则请求失败,并返回409 Conflict。

     

    2、局部更新

    使用更新请求最简单的一种用途就是添加新数据。新的数据会被合并到现有数据中,而如果存在相同的字段,就会被新的数据所替换。

    例如我们可以为我们的博客添加tags和views字段:

    POST /website/blog/1/_update
    {
       "doc" : {
          "tags" : [ "testing" ],
          "views": 0
       }
    }

    ES还可以使用脚本来更新文档,例如:

    POST /sina/employee/11412/_update
    {
       "script" : "ctx._source.age+=1"
    }

    更新一篇可能不存在的文档,使用upsert参数来设定文档不存在时,它应该被创建:

    POST /website/pageviews/1/_update
    {
       "script" : "ctx._source.views+=1",
       "upsert": {
           "views": 1
       }
    }

     

    3、检索文档(GET请求)

    例如:

    curl "127.0.0.1:9200/sina/employee/11412" 

    返回值:

    {"_index":"sina","_type":"employee","_id":"11412","_version":1,"found":true,"_source":{"name":"chenqi","age":30}}

    如果请求一个不存在的文档,如:

    curl "127.0.0.1:9200/sina/employee/11410"

    则返回:

    {"_index":"sina","_type":"employee","_id":"11410","found":false}

    也可以检索所有文档(不指定文档ID或类型ID),例如:

    URL说明
    /_search 搜索所有的索引和类型
    /gb/_search 搜索索引gb中的所有类型
    /gb,us/_search 搜索索引gb以及us中的所有类型
    /g*,u*/_search 搜索所有以gu开头的索引中的所有类型
    /gb/user/_search 搜索索引gb中类型user内的所有文档
    /gb,us/user,tweet/_search 搜索索引user以及tweet中类型gb and us内的所有文档
    /_all/user,tweet/_search 搜索所有索引中类型为user以及tweet内的所有文档

    注意:当我们在索引一个文档的时候,ES会将所有字段的值都汇总到一个大的字符串中,并将它索引成一个特殊的字段_all:

    {
        "tweet":    "However did I manage before Elasticsearch?",
        "date":     "2014-09-14",
        "name":     "Mary Jones",
        "user_id":  1
    }

    就好像我们已经添加了一个叫做_all的字段:

    "However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1"

    利用all字段,可以检索包含指定字符串的文档,如下面,搜索包含mary的文档:

    GET /_search?q=mary

    还可以根据指定字段来检索文档:

    http://10.69.2.49:9200/_search?q=age:28

    只返回字段age=28的文档;

    字段前加前缀"+"表示必须要满足我们的查询匹配条件,而前缀"-"则表示绝对不能匹配条件。没有+或者-的表示可选条件。匹配的越多,文档的相关性就越大。

    再实现一个复杂查询:

    • 字段name包含"mary""john"
    • date大于2014-09-10
    • _all字段中包含"aggregations""geo"
    q=+name:(mary john) +date:>2014-09-10 +(aggregations geo)

    另外,size和from参数可以控制翻页:

    参数说明
    size 每次返回多少个结果,默认值为10
    from 忽略最初的几条结果,默认值为0

    假设每页显示5条结果,那么1至3页的请求就是:

    GET /_search?size=5
    GET /_search?size=5&from=5
    GET /_search?size=5&from=10

    最后,使用source参数可以指定只返回文档的某几个字段,例如:

    http://10.69.2.49:9200/_search?q=age:28&_source=name
    http://10.69.2.49:9200/sina/employee/11412/_source

    4、检查文档(HEAD请求)

    curl -i -XHEAD /{index}/{type}/{id}

    存在返回200,否则返回404。

    5、删除文档(DELETE请求):

    curl "127.0.0.1:9200/sina/employee/11412" -XDELETE

    删除文档也会增加_version字段。 

    3、搜索

    前面提到了可以在GET请求中以q=field:value 的形式进行简易查询,此外,ES还提供了更加强大的Query DSL(Domain Specific Language)查询语言,通过它可以完成更加复杂的搜索任务。

    例如下面两种查询方式等价:

    curl "127.0.0.1:9200/sina/_search" -d '{"query":{"match":{"age":28}}}'
    
    curl "127.0.0.1:9200/sina/_search?q=age:28"

    其中,json串{"query":{"match":{"age":28}}} 就是一个Query DSL。

    下面是一个更为复杂的Query DSL,用于找到name字段等于"chenqi"的文档,并且附加了一个过滤条件:age>30。

    {
        "query":{
            "filtered":{
                "filter":{
                    "range":{
                    "age":{"gt":30}
                    }
                },
            
                "query":{
                    "match":{
                    "name":"chenqi"
                    }
                }
            }
        }
    }

    注:将match换成match_phrase,可以进行段落或短语的精确匹配。

    4、冲突处理

    Elasticsearch是分布式的。当文档被创建、更新或者删除时,新版本的文档就会被复制到集群中的其他节点上。ES即是同步的又是异步的,也就是说复制的请求被平行发送出去,然后可能会混乱地到达目的地。这就需要一种方法能够保证新的数据不会被旧数据所覆盖。

    我们在上文提到每当有索引、put和删除的操作时,无论文档有没有变化,它的_version都会增加。Elasticsearch使用_version来确保所有的改变操作都被正确排序。如果一个旧的版本出现在新版本之后,它就会被忽略掉。

    我们可以利用_version的优点来确保我们程序修改的数据冲突不会造成数据丢失。我们可以按照我们的想法来指定_version的数字。如果数字错误,请求就是失败。

     

    我们来创建一个新的博文:

    PUT /website/blog/1/_create
    {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
    }

    此时,文档的version=1;

    现在,我们试着重新索引文档以保存变化,我们这样指定了version的数字:

    PUT /website/blog/1?version=1
    {
      "title": "My first blog entry",
      "text":  "Starting to get the hang of this..."
    }

    当索引中文档的_version1时,更新才生效,更新后version=2。

    当我们再执行同样的索引请求,并依旧指定version=1时,ES就会返回一个409 Conflict的响应码,返回内容如下:

    {
      "error" : "VersionConflictEngineException[[website][2] [blog][1]:
                 version conflict, current [2], provided [1]]",
      "status" : 409
    }

    这里面指出了文档当前的_version数字是2,而我们要求的数字是1

    所有的有关于更新或者删除文档的API都支持version这个参数,有了它你就通过修改你的程序来使用并发控制。

     

     

     

     参考文档:

    http://www.learnes.net/data/mget.html

     

     

  • 相关阅读:
    949. Largest Time for Given Digits
    450. Delete Node in a BST
    983. Minimum Cost For Tickets
    16. 3Sum Closest java solutions
    73. Set Matrix Zeroes java solutions
    347. Top K Frequent Elements java solutions
    215. Kth Largest Element in an Array java solutions
    75. Sort Colors java solutions
    38. Count and Say java solutions
    371. Sum of Two Integers java solutions
  • 原文地址:https://www.cnblogs.com/chenny7/p/4311194.html
Copyright © 2011-2022 走看看