• ElasticSearch 进阶


    ElasticSearch 进阶

    SearchAPI

    ES 支持两种基本方式检索 :

    • 一个是通过使用 REST request URI 发送搜索参数(uri+检索参数)
    • 一个是通过使用 REST request body 来发送它们(uri+请求体)

    检索信息

    请求参数 详情
    GET bank/_search 检索 bank 下所有信息,包括 type 和 docs
    GET bank/_search?q=*&sort=account_number:asc 请求参数方式检索
    响应结果解释:
    took - Elasticsearch 执行搜索的时间(毫秒)
    time_out - 告诉我们搜索是否超时
    _shards - 告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片
    hits - 搜索结果
    hits.total - 搜索结果
    hits.hits - 实际的搜索结果数组(默认为前 10 的文档) 
    sort - 结果的排序 key(键)(没有则按 score 排序) 
    score 和 max_score –相关性得分和最高得分(全文检索用)
    
    • uri+请求体
    # GET查询 kibana查询
    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "account_number": "asc"
        },
        {
          "balance": "desc"
        }
      ]
    }
    
    HTTP 客户端工具(POSTMAN),get 请求不能携带请求体,我们变为 post 也是一样的我们 POST 一个 JSON 风格的查询请求体到 _search API。
    需要了解,一旦搜索的结果被返回,Elasticsearch 就完成了这次请求,并且不会维护任何
    服务端的资源或者结果的 cursor(游标)
    

    Query DSL

    基本语法格式

    Elasticsearch 提供了一个可以执行查询的 Json 风格的 DSL(domain-specific language 领域特定语言)。这个被称为Query DSL。该查询语言非常全面,并且刚开始的时候感觉有点复杂, 学好它的方法是从一些基础的示例开始的。

    # 查询语句
    {
      QUERY_NAME: { 
        ARGUMENT: VALUE, 
        ARGUMENT: VALUE,
        ...
      }
    }
    
    # 查询语句-针对某个字段
    {
      QUERY_NAME: { 
        FIELD_NAME: {
          ARGUMENT: VALUE, 
          ARGUMENT: VALUE,
          ...
        }
      }
    }
    

    查询-match

    # kibana查询
    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "from": 0,
      "size": 5,
      "sort": [
        {
          "account_number": {
            "order": "desc"
          }
        }
      ]
    }
    
    query :定义查询
    match_all 查询类型: 代表查询所有的所有
    from+size 限定: 分页功能
    sort : 排序
    
    # kibana查询-返回部分字段
    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "from": 0,
      "size": 5,
      "_source": ["age","balance"]
    }
    
    # kibana查询-match查询
    基本类型(非字符串),精确匹配;match 返回 account_number=20 的数据
    GET bank/_search
    {
      "query": {
        "match": {
          "account_number": "20"
        }
      }
    }
    
    # kibana查询-字符串查询
    最终查询出 address 中包含 mill 单词的所有记录
    GET bank/_search
    {
      "query": {
        "match": {
          "address": "mill"
        }
      }
    }
    
    注: match 当搜索字符串类型的时候,会进行全文检索,并且每条记录有相关性得分。
    
    # 字符串,多个单词(分词+全文检索)
    
    

    查询-match_phrase

    不分词匹配

    # 查出 address 中包含 mill road 的所有记录,并给出相关性得分
    GET bank/_search
    {
      "query": {
        "match_phrase": {
          "address": "mill road"
        }
      }
    }
    

    查询-multi_match

    多字段匹配

    # state 或 address 包含 mill 或 movico
    GET bank/_search
    {
      "query": {
        "multi_match": {
          "query": "mill Movico",
          "fields": ["state","address"]
        }
      }
    }
    

    查询-bool复合查询

    bool 用来做复合查询:
    复合语句可以合并任何它查询语句,包括复合语句,了解这一点是很重要的。
    复合语句之间可以互相嵌套,可以表达非常复杂的逻辑。

    # 查询address必须为mill age必须为28 lastname可为helloand也可不为helloand的数据
    
    # must:必须达到 must 列举的所有条件
    # must_not 必须不是指定的情况
    # should:应该达到 should 列举的条件,如果达到会增加相关文档的评分,并不会改变查询的结果。
    
    GET bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "address": "mill"
              }
            },
            {
              "match": {
                "gender": "M"
              }
            }
          ],
          "must_not": [
            {"match": {
              "age": "28"
            }}
          ],
          "should": [
            {
              "match": {
                "lastname": "Holland"
              }
            }
          ]
        }
      }
    }
    

    查询-filter过滤

    并不是所有的查询都需要产生分数,特别是那些仅用于 “filtering”(过滤)的文档。为了不计算分数 Elasticsearch 会自动检查场景并且优化查询的执行。

    GET bank/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "range": {
                "age": {
                  "gte": 18,
                  "lte": 30
                }
              }
            },
            {
              "match": {
                "address": "mill"
              }
            }
          ]
        }
      }
    }
    
    GET bank/_search
    {
      "query": {
        "bool": {
          "filter": [
            {
              "range": {
                "age": {
                  "gte": 18,
                  "lte": 30
                }
              }
            }
          ]
        }
      }
    }
    

    查询-term

    和 match 一样。匹配某个属性的值。全文检索字段用 match,其他非 text 字段匹配用 term。
    Term-query-Elasticsearch-Reference-7-5-Elastic.png

    # 检索时 非text字段则使用term
    GET bank/_search
    {
      "query": {
        "term": {
          "balance": "32838"
        }
      }
    }
    
    GET bank/_search
    {
      "query": {
        "match": {
          "balance": "32838"
        }
      }
    }
    

    Aggregations

    Aggregations结构:

    "aggregations" : {
        "<aggregation_name>" : {
            "<aggregation_type>" : {
                <aggregation_body>
            }
            [,"meta" : {  [<meta_data_body>] } ]?
            [,"aggregations" : { [<sub_aggregation>]+ } ]?
        }
        [,"<aggregation_name_2>" : { ... } ]*
    }
    

    Aggregations范例:

    # 搜索 address 中包含mill的所有人的年龄分布以及平均年龄,但不显示这些人的详情
    GET bank/_search
    {
      "query": {
        "match": {
          "address": "mill"
        }
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 10
          }
        },
        "ageAvg":{
          "avg":{
            "field":"age"
          }
        },
        "balanceAvg":{
          "avg": {
            "field": "balance"
          }
        }
      },
      "size": 0
    }
    
    # 按照年龄聚合,并且请求这些年龄段的这些人的平均薪资
    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 100
          },
          "aggs": {
            "ageAvg": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
    
    # 查出所有年龄分布,并且这些年龄段中 M 的平均薪资和 F 的平均薪资以及这个年龄段的总体平均薪资
    GET bank/_search
    {
      "query": {
        "match_all": {}
      },
      "aggs": {
        "ageAgg": {
          "terms": {
            "field": "age",
            "size": 100
          },
          "aggs": {
            "genderAgg": {
              "terms": {
                "field": "gender.keyword",
                "size": 10
              },
              "aggs": {
                "balanceAvg": {
                  "avg": {
                    "field": "balance"
                  }
                }
              }
            },
            "ageBalanceAvg":{
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
    

    Mapping

    Mapping 是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和索引的。

    查看索引
    # 查看 mapping 信息 kibana dev Tools执行
    GET bank/_mapping
    
    创建索引

    创建索引-创建索引并指定映射

    PUT /my_index
    {
      "mappings": {
        "properties": {
          "age": {"type": "integer"},
          "email": {"type": "keyword"},
          "name": {"type": "text"}
        }
      }
    }
    
    添加新字段映射
    # 添加新字段映射
    PUT /my_index/_mapping
    {
      "properties":{
        "employee_id":{
          "type":"keyword",
          "index":false
        }
      }
    }
    
    更新映射

    images/Mapping-Elasticsearch-Reference-7-5-Elastic.png
    对于已经存在的映射字段,我们不能更新。更新必须创建新的索引进行数据迁移

    # 查看存在映射
    GET /my_index/_mapping
    
    GET /bank/_search
    
    # 更新索引映射
    PUT /newbank
    {
      "mappings": {
        "properties": {
          "account_number": {
            "type": "long"
          },
          "address": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          },
          "balance": {
            "type": "long"
          },
          "city": {
            "type": "keyword"
          },
          "email": {
            "type": "keyword"
          },
          "employer": {
            "type": "keyword"
          },
          "firstname": {
            "type": "text"
          },
          "gender": {
            "type": "keyword"
          },
          "lastname": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "state": {
            "type": "keyword"
          }
        }
      }
    }
    
    # 获取新索引
    GET /newbank/_mapping
    
    数据迁移

    先创建出 new_twitter的正确映射。
    数据迁移格式:

    # elasticsearch 新版本数据迁移
    POST _reindex	[固定写法]
    {
        "source": {
            "index": "twitter"
        },
        "dest": {
            "index": "new_twitter"
        }
    }
    
    # elasticsearch 老版本数据迁移
    # 旧索引的 type 下的数据进行迁移
    POST _reindex
    {
        "source": {
            "index": "twitter",
            "type": "tweet"
        },
        "dest": {
            "index": "tweets"
        }
    }
    

    数据迁移:

    # 查看存在映射
    GET /my_index/_mapping
    
    GET /bank/_search
    
    # 更新索引映射
    PUT /newbank
    {
      "mappings": {
        "properties": {
          "account_number": {
            "type": "long"
          },
          "address": {
            "type": "text"
          },
          "age": {
            "type": "integer"
          },
          "balance": {
            "type": "long"
          },
          "city": {
            "type": "keyword"
          },
          "email": {
            "type": "keyword"
          },
          "employer": {
            "type": "keyword"
          },
          "firstname": {
            "type": "text"
          },
          "gender": {
            "type": "keyword"
          },
          "lastname": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "state": {
            "type": "keyword"
          }
        }
      }
    }
    
    GET /newbank/_mapping
    
    # 数据迁移 老版本迁移
    POST _reindex
    {
      "source": {
        "index": "bank",
        "type": "account"
      },
      "dest": {
        "index": "newbank"
      }
    }
      
    GET /newbank/_search
    
    # 不用type 老数据可以迁移过来
    

    分词

    一个 tokenizer(分词器)接收一个字符流,将之分割为独立的 tokens(词元,通常是独立的单词),然后输出 tokens 流。

    例如,whitespace tokenizer 遇到空白字符时分割文本。它会将文本 "Quick brown fox!" 分割为[Quick, brown, fox!]。

    该 tokenizer(分词器)还负责记录各个 term(词条)的顺序或 position 位置(用于 phrase 短语和 word proximity 词近邻查询),以及 term(词条)所代表的原始 word(单词)的 start
    (起始)和 end(结束)的 character offsets(字符偏移量)(用于高亮显示搜索的内容)。Elasticsearch 提供了很多内置的分词器,可以用来构建custom analyzers(自定义分词器)。

    # 支持英文分词器 对中文的分词不友好
    POST _analyze
    {
      "analyzer": "standard",
      "text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
    }
    

    安装IK分词器

    IK分词器下载-点我传送

    # wget下载 /mydata/elasticsearch/plugin
    $ wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
    
    # 进入docker容器
    $ docker exec -it elasticsearch /bin/bash
    $ cd /bin/
    $ elasticsearch-plugin
    $ elasticsearch-plugin -h
    
    # 列出系统的分词器
    $ elasticsearch-plugin list
    
    # 重启容器
    $ docker restart elasticsearch
    

    测试IK分词器

    # ik分词器
    POST _analyze
    {
      "analyzer": "ik_max_word",
      "text": "我是中国人"
    }
    
    # ik分词器
    POST _analyze
    {
      "analyzer": "ik_smart",
      "text": "我是中国人"
    }
    

    自定义词库

    修改/mydata/elasticsearch/plugins/elasticsearch-analysis-ik-7.4.2/config中的 IKAnalyzer.cfg.xml

    # IKAnalyzer.cfg.xml 配置文件内容
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    <properties>
            <comment>IK Analyzer 扩展配置</comment>
            <!--用户可以在这里配置自己的扩展字典 -->
            <entry key="ext_dict"></entry>
             <!--用户可以在这里配置自己的扩展停止词字典-->
            <entry key="ext_stopwords"></entry>
            <!--用户可以在这里配置远程扩展字典 -->
            <!-- <entry key="remote_ext_dict">words_location</entry> -->
            <!--用户可以在这里配置远程扩展停止词字典-->
            <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
    </properties>
    

    添加自定义词库:

    # 获取 自定义词库的地址 一般是安装在nginx上
    http://192.168.188.128/es/fenci.txt
    
    # IK config配置
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    <properties>
            <comment>IK Analyzer 扩展配置</comment>
            <!--用户可以在这里配置自己的扩展字典 -->
            <entry key="ext_dict"></entry>
             <!--用户可以在这里配置自己的扩展停止词字典-->
            <entry key="ext_stopwords"></entry>
            <!--用户可以在这里配置远程扩展字典 -->
            <entry key="remote_ext_dict">http://192.168.188.128/es/fenci.txt</entry>
            <!--用户可以在这里配置远程扩展停止词字典-->
            <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
    </properties>
    
    # 重启elasticsearch、nginx
    $ docker restart elasticsearch
    $ docker restart nginx
    
  • 相关阅读:
    HDU 3729【二分匹配】
    51nod 1456【强连通,缩点,并查集】
    51nod1459【二级最短路】
    51nod1640 【最小生成树】
    CodeForces660B【模拟—水】
    CodeForces691C 【模拟】
    Codeforces698B【并查集+拆环】
    CodeForces717C 【数学】
    Codeforces710C【数学】
    HDU5904【瞎搞】
  • 原文地址:https://www.cnblogs.com/HOsystem/p/14508970.html
Copyright © 2020-2023  润新知