• ElasticSearch从入门到精通--第六话(补充篇:Docker启动es、Kibana、IK分词器使用、地理位置、分数查询设置、聚合)


    ElasticSearch从入门到精通–第六话(补充篇:Docker启动es、Kibana、IK分词器使用、地理位置、分数查询设置、聚合)

    elasticsearch是ELK的核心,负责存储、搜索、分析数据(ELK包含:Elasticsearch、Logstash(数据抓取)、Kibana(数据可视化))

    es底层是Lucene实现,Lucene是一个Java语言的搜索引擎类库,优势:

    • 易扩展
    • 高性能(基于倒排索引)

    es优势:

    • 支持分布式,可水平扩展
    • 提供Restful接口,可被任意语言调用

    倒排索引

    词条文档id对应起来,形成反向索引

    在这里插入图片描述

    查询数据时,会先将关键词用分词器进行拆分,然后将拆分的多个词条,依次在倒排表中查询对应的文档id,再拿着id查询

    ES核心

    索引

    • 索引:相同类型的文档的集合
    • 映射:索引中文档的字段约束信息,类似表的结构约束

    在这里插入图片描述

    Docker启动单点ES

    • 创建docker网络(后面确保es和kibana在同一网络互通)

      docker network create es-net
      
      • 1
    • 拉取镜像

      docker pull elasticsearch:7.17.7
      docker pull kibana:7.17.7
      
      • 1
      • 2
    • 启动运行容器

      启动es

      docker run -d \
          --name es \
          -e "discovery.type=single-node" \
          -v es-data:/usr/share/elasticsearch/data \
          -v es-plugins:/usr/share/elasticsearch/plugins \
          --privileged \
          --network es-net \
          -p 9200:9200 \
          -p 9300:9300 \
      elasticsearch:7.12.1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      -e设置环境变量,discovery.type=single-node,单节点模式

      启动kibana

      docker run -d \
          --name kibana \
          -e ELASTICSEARCH_HOSTS=http://es:9200 \
          --network es-net \
          -p 5601:5601 \
      kibana:7.12.1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    ES分词器

    es创建倒排索引时需要对文档分词;但默认的分词规则对中文处理不友好。我们可以在设置分词,执行DSL语句

    POST请求至 /_analyze

    {
        "analyzer": "standard",	// 使用默认分词器
        "text": "学习es的很多天"
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    可以看到,学习es的很多天,被一个一个字拆分了,对中文分词来讲不太友好。

    我们可以使用其他的分词器插件,如IK分词器,使用时需要先将ik的插件包放到es的plugins包下面。

    • 先解压unzip -d ik elasticsearch-analysis-ik-7.12.1.zip,解压至ik文件夹

    • 按照上面的docker启动的话,我们需要把ik包放到es-plugins

      # 查看es-plugins数据卷,找到对应的位置为 /var/lib/docker/volumes/es-plugins/_data
      docker volume inspect es-plugins 
      
      # 将ik拷贝至es的plugins目录下
      cp -r ik/ /var/lib/docker/volumes/es-plugins/_data
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 然后重启es容器即可。

      # 重启es
      docker restart es
      
      # 查看es日志
      docker logs -f es
      
      • 1
      • 2
      • 3
      • 4
      • 5

    Ik分词器有两种模式:

    • ik_smart: 最少切分
    • ik_max_word:最细切分

    再次尝试分词

    POST请求至 /_analyze

    {
        "analyzer": "ik_smart",
        "text": "学习es的很多天"
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    OK,智能切分。再试试ik_max_word

    {
        "analyzer": "ik_max_word",
        "text": "学习es的很多天"
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    这种模式,会将所有的词细粒度拆分,会产生更多的词条,会占有更多的内存。

    IK分词器扩展

    像ik分词器分词时会去查询字典,是否是一个词汇。但是像一些网络用语等,字典是没有的,那么我们如何扩展呢?

    需要修改ik分词器目录中config/IKAnalyzer.cfg.xml文件

    
    DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    <properties>
            <comment>IK Analyzer 扩展配置comment>
            
            <entry key="ext_dict">ext.dicentry>
             
            <entry key="ext_stopwords">stopword.dicentry>
            
            
            
            
    properties>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    新建ext.dic文件,分别加入要扩展的

    ext.dic

    白嫖
    奥利给
    
    • 1
    • 2

    stopword.dic中加入要剔除的词汇

    ....
    的
    哦
    了
    
    • 1
    • 2
    • 3
    • 4

    重启es服务

    docker restart es
    
    • 1

    启动后,再次分词尝试

    {
        "analyzer": "ik_max_word",
        "text": "学习es的很多天,白嫖,奥利给"
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    网络词汇被合成了。

    ES mapping

    在这里插入图片描述

    • 在es中没有数组类型,所有字段都可以有多个值,只需要确定数组元素的类型即可,es会自动识别,多个值时在Java中还是用集合接收即可。

    • 而且object类型中的字段值,也会被进行索引。

    • index:设置为false时,将不会被加入倒排索引中,无法被索引(一些秘密数据)

    • analyzer:设置使用的分词器

    • properties:设置子字段,如上图的name中的firstNamelastName

    创建索引示例:

    在这里插入图片描述

    索引

    索引一旦被创建,是无法进行修改字段和映射的,但是可以添加新的字段

    PUT /索引名/_mapping
    {
    	"properties":{
    		"新字段":{
    			"type": "integer"
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其中es的mapping中有geo_point的类型(一个字符串,存放经纬度信息),查询时可按照地理查询法:

    • geo_bounding_box:查询geo_point值在某个矩形范围的所有文档
    • geo_distance:查询指定中心点,小于某个距离值的所有文档(附近的人)
    GET /indexName/_search
    {
        "query":{
            "geo_distance":{
                "distance": "15km",
                "FIELD": "经度,纬度值"	// 文档中的某个geo_point字段和值
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    DSL

    相关性

    当我们查询时,文档结果会根据与搜索磁条的关联度打分(_score),返回结果时按照分值降序排列。

    可认为手动设置加分,让其排名靠前,利用function score query

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BEZasz88-1668157785845)(C:/Users/EDZ/Desktop/文档/微服务/imgs/22.png)]

    function score query使用:

    • 过滤条件:哪些文档要加分
    • 算分函数:使用weight即可
    • 加权方式:function score和query score如何进行运算

    ES分页

    • from+size:深度分页问题,from+size<=10000
    • after search:从排序值开始查,能破万,但只能向后查询
    • scroll:被淘汰,占用内存,结果非实时

    ES高亮

    高亮查询,默认情况下,ES搜索的字段,必须要与高亮字段一致

    可以将默认的设置为false

    {
        "query":{
          "match":{
              "all":"哈哈"
          }
        },
        "highlight":{
            "fields":{
               "name":{
                   "require_field_match": "false"
               }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    地理位置原生API

    request.source().sort(SortBuilders
                          .geoDistanceSort("location", new GeoPoint("31.21, 121.5"))
                          .order(SortOrder.ASC)
                          .unit(DistanceUnit.KILOMETERS)
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    指定排名打分

    SearchRequest request = new SearchRequest("user");
    
    FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
        // 原始查询
        QueryBuilders.matchQuery("all", "a")
        // function score数组
        , new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
            new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                QueryBuilders.termQuery("isAD", true),	// 字段isAD为true的,需要加分
                ScoreFunctionBuilders.weightFactorFunction(10)
            )
        });
    
    request.source().query(functionScoreQueryBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    聚合

    在这里插入图片描述

    • 在这里插入图片描述

      request.source().size(0); // 不返回任何source文档
      request.source().aggregation(AggregationBuilders
                      .terms("title_agg")
                      .field("title")
                      .size(20));
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 管道
      在这里插入图片描述

    聚合结果解析

    在这里插入图片描述

    request.source().aggregation(AggregationBuilders
                                 .terms("title_agg")
                                 .field("title")
                                 .size(20));
    Aggregations aggregations = response.getAggregations();
    Terms titleAgg = aggregations.get("title_agg");
    List<? extends Terms.Bucket> buckets = titleAgg.getBuckets();
    for (Terms.Bucket bucket : buckets) {
        // 获取Key,也就是title字段
        System.out.println(bucket.getKeyAsString());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    多聚合条件

    request.source().aggregation(AggregationBuilders
                                 .terms("title_agg")
                                 .field("title")
                                 .size(20));
    
    request.source().aggregation(AggregationBuilders
                                 .terms("brand_agg")
                                 .field("brand")
                                 .size(20));
    
    request.source().aggregation(AggregationBuilders
                                 .terms("xxx_agg")
                                 .field("xxx")
                                 .size(20));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    带过滤条件的聚合

    // 添加查询条件
    request.source().query(QueryBuilders.termQuery("title", "a"));
    // 添加聚合
    request.source().aggregation(AggregationBuilders
            .terms("title_agg")
            .field("title")
            .size(20));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    (40)Verilog实现序列10111【状态机三段式】
    设计模式——模板方法模式、策略模式(行为型模式)
    简单又有效的基本折线图制作方法
    【Rust】——Vector集合
    KMP算法(题目)
    【计算机毕业设计】27.仓库管理系统源码
    最小生成树拓展应用之:【令建虚拟点n-->n+1】
    230921整合支付宝支付
    VsCode个人插件
    聊聊交互设计师的成长 优漫动游
  • 原文地址:https://blog.csdn.net/weixin_45248492/article/details/127809677