ElasticSearch入门

作者: fanyank | 来源:发表于2018-11-11 19:10 被阅读1次

    ElasticSearch笔记

    ElasticSearch.jpg

    前言

    Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库--无论是开源还是私有。

    但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理。Lucene 非常 复杂。

    Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单, 通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。

    然而,Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:

    • 一个分布式的实时文档存储,每个字段 可以被索引与搜索
    • 一个分布式实时分析搜索引擎
    • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

    Elasticsearch 将所有的功能打包成一个单独的服务,这样你可以通过程序与它提供的简单的 RESTful API 进行通信, 可以使用自己喜欢的编程语言充当 web 客户端,甚至可以使用命令行(去充当这个客户端)。

    就 Elasticsearch 而言,起步很简单。对于初学者来说,它预设了一些适当的默认值,并隐藏了复杂的搜索理论知识。 它 开箱即用 。只需最少的理解,你很快就能具有生产力

    本文基于ElasticSearch 2.2,参考自https://www.elastic.co/guide/en/elasticsearch/reference/2.2/getting-started.html

    基础知识

    1. Near RealTime
      Elastic是一种实时搜索引擎

    2. Cluster
      集群是各个节点的集合,保存了所有的数据并提供了数据检索能力。

      • 默认集群的名称是elasticsearch
      • 集群名称不可重复
      • 每个集群至少有一个节点
    3. Node
      多个节点构成了集群,集群的数据存储和数据检索也是依赖于节点来完成的,节点的名称是一个随机值,当然你也可以自己修改咯

      • 节点默认加入elasticsearch集群
      • 一个集群的拥有的节点数量不做限制
      • 如果网络上没有一个节点,那么此时新建一个节点将默认加入到elasticsearch集群中
    4. Index
      索引是document的集合,通过索引你可以查询,更新,删除document

      • 索引的名称必须全部是小写
      • 集群中你可以定义多个index
    5. Type
      Type可以理解为Java中的类,Document就是通过该类创建出来的实例

    6. Document
      Document是可以被检索到的最小数据单元集合

      • Document数据全部是JSON格式
      • Document必须指定其对应type
    7. Shards
      数据分片,提供了index数据量无限增大的能力。出现数据分片的原因:单个node容不下某个index中所有的数据。

    8. Replicas
      既然有了数据分片,也就意味着数据不在同一个物理节点上存储,那么某次查询就会可能出现某个数据分片所在的节点挂掉的情况,此时的解决方案就是进行数据复制

      • 默认情况下,elasicsearch有5个数据分片和1次复制,这就意味着如果集群中只有两个nodeA和B,加入nodeA保存着源数据,那么经过一个数据复制之后,nodeB中也会存在一份相同的数据

    启动ElasticSearch

    在bin目录下执行

    ./elasticsearch
    

    启动时修改集群名称和节点名称

    ./elasticsearch --cluster.name fanyank_cluster --node.name fanyank_node1
    

    探索ElasticSearch

    1. 执行健康检查

      curl "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 
      1541906922 11:28:42  elasticsearch green           1         1      0   0    0    0        0             0                  -                100.0% 
      
      • status: green(正常),yellow(集群整体可用,但某些复制节点有问题),red(集群不可用)
    2. 查询所有节点

      curl "localhost:9200/_cat/nodes?v"
      

      执行成功之后可以看到

      host      ip        heap.percent ram.percent  load node.role master name       
      127.0.0.1 127.0.0.1            4          81 -1.00 d         *      Nightshade 
      
    3. 查询所有index

      curl "localhost:9200/_cat/indices?v"
      

      执行成功之后可以看到

      health status index pri rep docs.count docs.deleted store.size pri.store.size 
      

      意味着我们目前还没有建立任何索引

    4. 建立index
      建立名称为customer的index

      curl -XPUT 'localhost:9200/customer?pretty'
      curl 'localhost:9200/_cat/indices?v'
      

      执行之后可以看到

      health status index    pri rep docs.count docs.deleted store.size pri.store.size 
      yellow open   customer   5   1          0            0       650b           650b
      

      我们可以得知customer索引现在有5个数据分片和1次复制,包含了0个文档。另外,health状态为yellow,这是因为我们现在只有一个node,而复制操作至少需要两个node,所以replica是连接不上的,所以状态为yellow

    5. 插入document
      在插入数据前,必须指定数据的type。现在我们在customer索引中插入一个类型为external的数据,并且数据的ID为1
      插入的JSON数据 {"name":"fanyank"}

      curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '{"name" : "fanyank"}'
      

      执行之后可以看到

      {
          "_index" : "customer",
          "_type" : "external",
          "_id" : "2",
          "_version" : 1,
          "_shards" : {
              "total" : 2,
              "successful" : 1,
              "failed" : 0
          },
          "created" : true
      }
      

      插入数据时注意,elasticsearch不会检查索引是否存在,如果发现索引不存在,那么elasticsearch会自动创建索引并插入,所以执行插入时一定要检查索引名称是否拼写正确。

      我们在插入数据时也可以不指定ID,这样elasticsearch会为我们生成一个唯一的hashcode,注意此时使用的http请求是POST

      curl -XPOST 'localhost:9200/customer/external?pretty' -d '{"name" : "fanyank"}'
      

      执行之后返回如下

      {
          "_index" : "customer",
          "_type" : "external",
          "_id" : "AWcBDGmpUlH0QZg74qVp",
          "_version" : 1,
          "_shards" : {
              "total" : 2,
              "successful" : 1,
              "failed" : 0
          },
          "created" : true
      }
      
    6. 更新数据
      更新数据和插入数据一样,如果发现id已经存在,那么elasticsearch就会执行更新操作
      elasticsearch执行更新操作的本质是删除已有数据然后新插入一条数据

      1. 方法一

        curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '{"name":"Big Bang"}'
        
      2. 方法二

        curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '{"doc":{"name":"Nathan James"}}'
        
      3. 方法三
        在external中添加age字段

        curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '{"doc":{"name":"Nathan James","age":20}}'
        
      4. 方法四
        使用script

        curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '
        {
            "script" : "ctx._source.age += 5"
        }'
        

        注意方法二,方法三请求是POST请求,而且请求体包含doc字段

    7. 查询数据
      查询我们刚刚插入的id为1的数据

      curl 'localhost:9200/customer/external/1?pretty'
      

      执行之后返回如下

      {
          "_index" : "customer",
          "_type" : "external",
          "_id" : "2",
          "_version" : 4,
          "found" : true,
          "_source" : {
              "name" : "fanyank"
          }
      }
      
    8. 删除index

      curl -XDELETE 'localhost:9200/customer?pretty'
      curl 'localhost:9200/_cat/indices?v'
      
    9. 删除document

      curl -XDELETE 'localhost:9200/customer/external/2?pretty'
      
    10. 批处理
      批处理可以在一次请求中对多个document完成插入,更新,删除操作
      如下示例在一次请求中插入了一条数据{"name":"Alice"},更新一条数据{"name":"tom","age",16},删除一条数据{"_id":"1"}

      curl -XPOST 'localhost:9200/customer/external/_bulk?pretty' -d '
      {"index":{"_id":"3"}}
      {"name":"Alice"}
      {"update":{"_id":"2"}}
      {"doc":{"name:"tom","age":"16"}}
      {"delete":{"_id":"1"}}
      '
      

      这个不成功,稍后再试一下

    搜索API详解

    1. 搜索某个索引的全部数据

      curl 'localhost:9200/bank/_search?q=*&pretty'
      

      或者

      curl 'localhost:9200/bank/_search?pretty' -d '
      {
          "query" : {"match_all":{}}
      }
      '
      
    2. 限制返回的结果数量为100,默认限制的是10个

      curl 'localhost:9200/bank/_search?pretty' -d '
      {
          "query" : {"match_all":{}},
          "size": 100
      }
      '
      
    3. 分页
      返回下标为10往后的10个数据

      curl 'localhost:9200/bank/_search?pretty' -d '
      {
          "query" : {"match_all":{}},
          "from": 10,
          "size": 10
      }
      '
      
    4. 排序
      按照余额倒序排列

      curl 'localhost:9200/bank/_search?pretty' -d '
      {
          "query" : {"match_all":{}},
          "sort": { "balance": { "order": "desc" } }
      }
      '
      
    5. 限制返回的字段
      限制返回的字段只有account_number和balance

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { "match_all": {} },
      "_source": ["account_number", "balance"]
      }'
      
    6. 条件查询
      查询account_id为10010的账户

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { "match": {"account_id":"10010"} }
      }'
      
    7. 与查询
      查询address为test,且account_id为10010的账户

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { 
          "bool": {
              "must": [
                  {"match": {"account_id":"10010"}},
                  {"match": {"address": "test"}}
              ]
          }
       }
      }'
      
    8. 或查询
      查询account_id为10010或account_id为10011的账户

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { 
          "bool": {
              "should": [
                  {"match": {"account_id":"10010"}},
                  {"match": {"account_id": "10011"}}
              ]
          }
       }
      }'
      
    9. 非查询
      查询account_id不为10010和10011的账户

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { 
          "bool": {
              "must_not": [
                  {"match": {"account_id":"10010"}},
                  {"match": {"account_id": "10011"}}
              ]
          }
       }
      }'
      
    10. 组合查询(与或非)
      查询account_id不为10011,且address为test的账户

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { 
          "bool": {
              "must_not": [
                  {"match": {"account_id": "10011"}}
              ],
              "must": [
                  {"match": {"addrss": "test"}}
              ]
          }
       }
      }'
      
    11. 过滤器查询
      查询所有数据,并且过滤出ts在2017-11-14T13:08:40.000Z - 2017-12-14T13:08:40.000Z之间的数据

      curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
      {
      "query": { 
          "bool": {
              "must": [
                  {"match_all": {}
              ],
              "filter": {
                  "range": {
                      "ts": {
                          "gte": 2017-11-14T13:08:40.000Z
                          "lte": 2017-12-14T13:08:40.000Z
                      }
                  }
              }
          }
       }
      }'
      
    12. 聚合查询

      1. avg
        查询学生的平均成绩

        {
            "aggs": {
                "avg_grade": {
                    "avg": {
                        "field": "grade"
                    }
                }
            }
        }
        

        查询结果如下

        {
            ...
        
            "aggregations": {
                "avg_grade": {
                    "value": 75
                }
            }
        }
        
      2. count
        查询学生数量

        {
            "size": 0,
            "aggs": {
                "student_count": {
                    "cardinality": {
                        "field": "id"
                    }
                }
            }
        }
        

        查询结果如下:

        {
            ...
        
            "aggregations": {
                "student_count": {
                    "value": 100
                }
            }
        }
        
      3. stats
        统计学生成绩

        {
            "size": 0,
            "aggs": {
                "student_grade_stats": {
                    "extended_stats": {
                        "field": "grade"
                    }
                }
            }
        }
        

        查询结果如下:

        {
            ...
        
            "aggregations": {
                "grade_stats": {
                "count": 9,
                "min": 72,
                "max": 99,
                "avg": 86,
                "sum": 774,
                "sum_of_squares": 67028,
                "variance": 51.55555555555556,
                "std_deviation": 7.180219742846005,
                "std_deviation_bounds": {
                    "upper": 100.36043948569201,
                    "lower": 71.63956051430799
                }
                }
            }
        }
        
      4. bucket
        把学生按照性别进行分组

        {
            "size": 0,
            "aggs": {
                "genders": {
                    "terms": {
                        "field": "gender"
                    }
                }
            }
        }
        

        执行之后结果如下:

        {
            ...
        
            "aggregations" : {
                "genders" : {
                    "doc_count_error_upper_bound": 0, 
                    "sum_other_doc_count": 0, 
                    "buckets" : [ 
                        {
                            "key" : "male",
                            "doc_count" : 10
                        },
                        {
                            "key" : "female",
                            "doc_count" : 10
                        },
                    ]
                }
            }
        }
        
      5. 嵌套查询
        分别计算男生和女生的数学成绩的平均分

        {
            "aggs": {
                "groupby_gender": {
                    "terms": {
                        "field": "gender"
                    },
                    "aggs": {
                        "avg_math_score": {
                            "avg": {
                                "field": "math"
                            }
                        }
                    }
                }
            }
        }
        

        查询结果如下

        {
            ...
        
            "aggregations": {
                "groupby_gender": {
                "doc_count_error_upper_bound": 3,
                "sum_other_doc_count": 304,
                "buckets": [
                    {
                    "doc_count": 10,
                    "avg_math_score": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                        {
                            "doc_count": 1,
                            "key": 87
                        }
                        ]
                    },
                    "key": "male"
                    },
                    {
                    "doc_count": 9,
                    "avg_math_score": {
                        "doc_count_error_upper_bound": 0,
                        "sum_other_doc_count": 0,
                        "buckets": [
                        {
                            "doc_count": 1,
                            "key": 91
                        }
                        ]
                    },
                    "key": "female"
                    }
                 ]
                }
            }
        }
        

        某次搜索结果如下,借此说明各个字段的含义

        {
        "took": 63,
        "timed_out": false,
        "_shards": {
            "total": 5,
            "successful": 5,
            "failed": 0
        },
        "hits": {
            "total": 1000,
            "max_score": 1,
            "hits": [
            {
                "_index": "bank",
                "_type": "account",
                "_id": "1",
                "_score": 1,
                "_source": {
                "account_number": 1,
                "balance": 39225,
                "firstname": "Amber",
                "lastname": "Duke",
                "age": 32,
                "gender": "M",
                "address": "880 Holmes Lane",
                "employer": "Pyrami",
                "email": "amberduke@pyrami.com",
                "city": "Brogan",
                "state": "IL"
                }
            },
            {
                "_index": "bank",
                "_type": "account",
                "_id": "6",
                "_score": 1,
                "_source": {
                "account_number": 6,
                "balance": 5686,
                "firstname": "Hattie",
                "lastname": "Bond",
                "age": 36,
                "gender": "M",
                "address": "671 Bristol Street",
                "employer": "Netagy",
                "email": "hattiebond@netagy.com",
                "city": "Dante",
                "state": "TN"
                }
            }
            ]
        }
        }
        

        数据字典:

        • took: 查询花费的毫秒数
        • time_out: 查询是否超时
        • _shards: 查询所涉及到的数据分片的数量,成功数量和失败数量
        • hits: 查询结果
          • hits_.total: 返回的结果总数
          • hits.hits: 返回的结果,以数组形式返回
          • _score: 与查询参数匹配的程度
          • max_score: 最大匹配程度

    相关文章

      网友评论

        本文标题:ElasticSearch入门

        本文链接:https://www.haomeiwen.com/subject/eynxfqtx.html