zoukankan      html  css  js  c++  java
  • Elasticsearch中核心详解

    1.文档

      在Elasticsearch中,文档以JSON格式进行存储,可以是复杂的结构,如:

    {
        "_index": "haoke",
        "_type": "user",
        "_id": "1005",
        "_version": 1,
        "_score": 1,
        "_source": {
            "id": 1005,
            "name": "孙七",
            "age": 37,
            "sex": "女",
            "card": {
                "card_number": "123456789"
            }
        }
    }

        其中,card是一个复杂对象,嵌套的Card对象。

        元数据(metadata)

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

           _index:

            索引(index)类似于关系型数据库里的“数据库”——它是我们存储和索引关联数据的地方。

            注意:我们的索引被存储在分片(shards)中,索引只是把一个或多个分片组合在一起的逻辑空间。

          _type:

            在Elasticsearch中,使用相同类型(type)的文档表示相同的“事物”,因为他们的数据结构也是相同的。
            注意:_type 的名字可以是大写或小写,不能包含下划线或逗号。

          _id:

            id仅仅是一个字符串,它与 _index 和 _type 组合时,就可以在Elasticsearch中唯一标识一个文档。当创建一个文档,你可以自定义 _id ,也可以让Elasticsearch帮你自动生成。
    2.查询响应

      访问:http://192.168.43.182:9200/haoke/user/69AyEXEBVAiLr6jRzMgR

    {
        "_index": "haoke",
        "_type": "user",
        "_id": "69AyEXEBVAiLr6jRzMgR",
        "_version": 1,
        "found": true,
        "_source": {
            "id": 1004,
            "name": "赵六",
            "age": 19,
            "sex": "女"
        }
    }

      指定响应字段访问:

        GET /haoke/user/69AyEXEBVAiLr6jRzMgR?_source=id,name

    {
        "_index": "haoke",
        "_type": "user",
        "_id": "69AyEXEBVAiLr6jRzMgR",
        "_version": 1,
        "found": true,
        "_source": {
            "name": "赵六",
            "id": 1004
        }
    }

        如不需要返回元数据,仅仅返回原始数据,可以这样:

          GET /haoke/user/1005/_source

    {
        "id": 1004,
        "name": "赵六",
        "age": 19,
        "sex": "女"
    }

        也可以这样:GET /haoke/user/1005/_source?_source=id,name

    {
        "name": "赵六",
        "id": 1004
    }

    3.判断文档是否存在

      如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:

        HEAD /haoke/user/69AyEXEBVAiLr6jRzMgR

        

         如果不存在则返回404

    4.批量操作

      批量查询:

        POST /haoke/user/_mget

    {
        "ids" : [ "1001", "1003" ]
    }

          如果,某一条数据不存在,不影响整体响应,需要通过found的值进行判断是否查询到数据。

      _bulk操作:

        在Elasticsearch中,支持批量的插入、修改、删除操作,都是通过_bulk的api完成的。

        批量插入数据:POST /haoke/user/_bulk

    {"create":{"_index":"haoke","_type":"user","_id":2001}}
    {"id":2001,"name":"name1","age": 20,"sex": "男"}
    {"create":{"_index":"haoke","_type":"user","_id":2002}}
    {"id":2002,"name":"name2","age": 20,"sex": "男"}
    {"create":{"_index":"haoke","_type":"user","_id":2003}}
    {"id":2003,"name":"name3","age": 20,"sex": "男"}

          注意:最后必须有一个回车

        批量删除:POST /haoke/user/_bulk

    {"delete":{"_index":"haoke","_type":"user","_id":2001}}
    {"delete":{"_index":"haoke","_type":"user","_id":2002}}
    {"delete":{"_index":"haoke","_type":"user","_id":2003}}

          注意:最后必须有一个回车

        其他操作类似

      一次请求多少性能最高?
        整个批量请求需要被加载到接收我们请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。有一个最佳的bulk请求大小。超过这个大小,性能不再提升而且可能降低。
        最佳大小,当然并不是一个固定的数字。它完全取决于你的硬件、你文档的大小和复杂度以及索引和搜索的负载。
        幸运的是,这个最佳点(sweetspot)还是容易找到的:试着批量索引标准的文档,随着大小的增长,当性能开始降低,说明你每个批次的大小太大了。开始的数量可以在1000~5000个文档之间,如果你的文档非常大,可以使用较小的批次。
        通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。一个好的批次最好保持在5-15MB大小间。
    5.分页

      和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:

        size: 结果数,默认10
        from: 跳过开始的结果数,默认0

      如果你想每页显示5个结果,页码从1到3,那请求如下:

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

        应该当心分页太深或者一次请求太多的结果,结果在返回前会被排序。记住一个搜索请求常常涉及多个分片,每个分片生成自己排好序的结果,接着需要集中起来排序以确保整体排序正确。
        http://192.168.43.182:9200/haoke/user/_search?size=1&from=2

        

      在集群系统中深度分页
        假设在一个有5个主分片的索引中搜索。当我们请求结果的第一页(结果1到10)时,每个分片产生自己最顶端10个结果然后返回给它们请求节点(requesting node),它再排序这所有的50个结果以选出顶端的10个结果。
        现在假设我们请求第1000页——结果10001到10010。工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序这50050个结果并丢弃50040个!

        可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任何语句不能返回多于1000个结果的原因。
    6.映射

      前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类型的。
      自动判断的规则如下:

        

       Elasticsearch中支持的类型如下:

        

        string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
        text 类型,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
        keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合建议使用。keyword类型的字段只能通过精确值搜索到。
        创建明确类型的索引:
          PUT /fan

    {
        "settings": {
            "index": {
                "number_of_shards": "2",
                "number_of_replicas": "0"
            }
        },
        "mappings": {
            "person": {
                "properties": {
                    "name": {
                        "type": "text"
                    },
                    "age": {
                        "type": "integer"
                    },
                    "mail": {
                        "type": "keyword"
                    },
                    "bobby": {
                        "type": "text"
                    }
                }
            }
        }
    }

        查看映射:

          GET /fan/_mapping 

            

         插入数据:

          POST /fan/_bulk

    {"index":{"_index":"fan","_type":"person"}}
    {"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
    {"index":{"_index":"fan","_type":"person"}}
    {"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
    {"index":{"_index":"fan","_type":"person"}}
    {"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
    {"index":{"_index":"fan","_type":"person"}}
    {"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳"}
    {"index":{"_index":"fan","_type":"person"}}
    {"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影"}

            注意:最后必须有一个回车

          

    7.结构化查询

      term查询:

        term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):

          { "term": { "age": 26}}
          { "term": { "date": "2014-09-01" }}
          { "term": { "public": true }}
          { "term": { "tag":  "full_text" }}

        POST /fan/person/_search

    {
        "query": {
            "term": {
                "age": 20
            }
        }
    }

      terms查询:

        terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:

    {
        "query": {
            "terms": {
                "age": [20, 21, 22]
            }
        }
    }

      range查询:
        range 过滤,允许我们按照指定范围查找一批数据:

        范围操作符包含:
          gt :: 大于
          gte :: 大于等于
          lt :: 小于
          lte :: 小于等于

    {
        "query": {
            "range": {
                "age": {
                    "gte": 20,
                    "lt": 30
                }
            }
        }
    }

      exists 查询:
        exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件

        如果存在则返回相应的数据,否则返回空数据

    {
        "query": {
            "exists": {
                "field": "card"
            }
        }
    }

      match查询:
        match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
          如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析再进行查询字符:

    {
        "query": {
            "match": {
                "hobby": "羽毛球 兵乓球"
            }
        }
    }

          如果用 match 指定了一个确切值,在遇到数字,日期,布尔值或者 not_analyzed 的字符串时,它将为你搜索你给定的值:

            { "match": { "age":   26      }}
            { "match": { "date":  "2014-09-01" }}
            { "match": { "public": true     }}
            { "match": { "tag":   "full_text" }}

      bool查询:

        bool 查询可以用来合并前面的多个查询,它包含一下操作符:
          must :: 多个查询条件的完全匹配,相当于 and 。
          must_not :: 多个查询条件的相反匹配,相当于 not 。
          should :: 至少有一个查询条件匹配, 相当于 or 。

    {
        "query": {
            "bool": {
                "must": {
                    "match": {
                        "hobby": "足球"
                    }
                },
                "must_not": {
                    "hobby": "音乐"
                }
            }
        }
    }

    8.过滤查询

      查询年龄为20岁的用户:

    {  
        "query": {    
            "bool": {      
                "filter": {        
                    "term": {          
                        "age": 20       
                    }     
                }   
            } 
        }
    }

      查询和过滤的对比:
        一条过滤语句会询问每个文档的字段值是否包含着特定值。
        查询语句会询问每个文档的字段值与特定值的匹配程度如何。
          一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且按照相关性对匹配到的文档进行排序。
           这种评分方式非常适用于一个没有完全配置结果的全文本搜索。
        一个简单的文档列表,快速匹配运算并存入内存是十分方便的,每个文档仅需要1个字节。这些缓存的过滤结果集与后续请求的结合使用是非常高效的。
        查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比过滤语句更耗时,并且查询结果也不可缓存。
        建议:做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。

  • 相关阅读:
    redhat linux tftp
    mysql
    mysql操作!
    【Android】第一个JNI测试程序
    【android】【google map api v2】google 地图 api v2
    【Android】【转】内存耗用:VSS/RSS/PSS/USS
    【Android】获取Mac地址【2】
    【Android】每个Activity中加入引导界面
    【JNI】javah使用(初步)
    【Android】Eclipse svn插件安装说明
  • 原文地址:https://www.cnblogs.com/roadlandscape/p/12570944.html
Copyright © 2011-2022 走看看