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

     

     

  • 相关阅读:
    Weblogic 12c 集群部署和session复制
    Weblogic 12c 集群环境搭建
    Programming In Scala笔记-第十九章、类型参数,协变逆变,上界下界
    这是最好的时光,这是最坏的时光 SNAPSHOT
    这是最好的时光 这是最坏的时光 v0.1.1.1
    鹅厂欧阳大神给年轻人的一些分享
    谈到电影,我们收获了什么
    那些被电影搞的日子
    Programming In Scala笔记-第十五章、Case Classes和模式匹配
    [CSharp]传一个包含多个属性的对象,只改变其中个别属性值的方法
  • 原文地址:https://www.cnblogs.com/chenny7/p/4311194.html
Copyright © 2011-2022 走看看