• Elasticsearch高级检索之使用单个字母数字进行分词N-gram tokenizer(不区分大小写)【实战篇】


    一、前言

    小编最近在做到一个检索相关的需求,要求按照一个字段的每个字母或者数字进行检索,如果是不设置分词规则的话,英文是按照单词来进行分词的。

    小编以7.6.0版本做的功能哈,大家可以根据自己的版本去官网看看,应该区别不大

    例子:
    C6153PE-冬日恋歌,要可以通过任何一个数字和字母进行检索到,并且不区分大小写。c6c6等等!

    今天官网上有一些例子,觉得和实战还是有点区别,小编这里通过了测试抓紧来记录一下,希望帮助后来人哈!

    二、测试分词策略

    我们进入官网找到我们需要的策略:
    Elasticsearch策略官网

    N-gram 分词器
    每当遇到指定字符列表中的一个时,ngram标记器首先将文本分解为单词,然后发出 指定长度的每个单词的N-gram

    N-gram 就像一个在单词上移动的滑动窗口——一个指定长度的连续字符序列。它们对于查询不使用空格或复合词长的语言很有用。

    我们去kibana进行测试分词策略是否符合我们的要求:

    POST _analyze
    {
      "tokenizer": "ngram",
      "text": "C6153PE-冬日恋歌"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    分词分得细,会导致检索的效率降低,但是需求如此,没办法,最重要的是小编这里的数据量只有1w,其实换了这种分词,是无感知的!

    在这里插入图片描述
    分词策略规则:

    ngram分词器接受以下参数:

    参数解释
    min_gram以 gram 为单位的最小长度。默认为1.
    max_gram以 gram 为单位的最大字符长度。默认为2.
    token_chars应包含在令牌中的字符类,Elasticsearch 将根据不属于指定类的字符进行拆分。默认为[](保留所有字符)详细参数见下表
    custom_token_chars应被视为令牌一部分的自定义字符。例如,将此设置为±_将使标记器将加号、减号和下划线符号视为标记的一部分。

    min_gram将和设置max_gram为相同的值通常是有意义的。长度越小,匹配的文档越多,但匹配的质量越低。长度越长,匹配越具体。三元组(长度3)是一个很好的起点。官方比较推荐使用3,可能是因为效率分词粒度两不误吧,这里不符合小编的,小编这里使用是1,2,也就是默认的值

    token_chars参数解释例子
    letter字母,例如a, b,ï或京
    digit数字,例如3或7
    whitespace空白,例如" “或”\n"
    punctuation标点,例如!或"
    symbol标记, 例如$或√
    custom自定义,需要使用 custom_token_chars设置设置的自定义字符

    custom_token_chars
    应被视为令牌一部分的自定义字符。例如,将此设置为±_将使标记器将加号、减号和下划线符号视为标记的一部分。

    三、在索引字段中使用

    官方是使用一个字段进行测试的,这里小编就直接使用公司的索引进行演示了!
    这里是官网的例子:
    在这里插入图片描述
    下面放出来小编实战后的例子:

    总结就是在settings配置分词策略,在mappings中进行使用即可!!

    PUT /product
    {
      "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 0,
        "index": {
          "max_result_window": 100000000
        },
        # 这里使用分词策略
        "analysis": {
          "analyzer": {
            "my_analyzer": {
              # 这里分词指定下面策略的具体配置的名称
              "tokenizer": "my_tokenizer",
              # 这里忽略大小写配置
              "filter": [
                "lowercase"
              ]
            }
          },
          # 具体策略配置
          "tokenizer": {
            "my_tokenizer": {
              "type": "ngram",
              "min_gram": 1,
              "max_gram": 2,
              "token_chars": [
                "letter",
                "digit"
              ]
            }
          }
        }
      },
      "mappings": {
        "dynamic": "strict",
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "@version": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "cargoNo": {
            "type": "text"
          },
          "name": {
            "type": "text"
          },
          "sort": {
            "type": "integer"
          },
          "attribute13": {
            "type": "text",
            # 在需要的字段指定我们写的分词策略
            "analyzer": "my_analyzer"
          },
          "isDeleted": {
            "type": "integer"
          }
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    四、在springboot中实战

    为了公司,小编只粘贴部分条件构建规则:

    SearchRequest searchRequest = new SearchRequest("product");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    BoolQueryBuilder bool = new BoolQueryBuilder();
    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
    boolQueryBuilder.should(QueryBuilders.matchPhraseQuery("name", model))
             .should(QueryBuilders.matchPhraseQuery("cargoNo", model))
             .should(QueryBuilders.wildcardQuery("cargoNo", "*" + model + "*"))
             // 我们分词规则的字段查询
             .should(QueryBuilders.matchPhraseQuery("attribute13", model));
     bool.must(boolQueryBuilder);
     searchSourceBuilder.query(bool);
     searchRequest.source(searchSourceBuilder);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    我们拿着页面感受一下分词带来的效果:

    效果实现,随便一个字母都可以查询出来,这里只显示名称和一个数字,其实是使用attribute13来进行查询的,是因为attribute13是名称的第一个-之前的截出来的。

    在这里插入图片描述

    五、总结

    这样我们就完成了一些定制化的需求,完美交差,还得是看官网啊!!一定要去看官网!搜了好多都没有这种的教程,写出来帮助后来人,但是详细的还得是看官网哈!小编这里也是把官网的一些概念写到了博客里!!

    如果对你有帮助还请不要吝啬你的发财小手给小编来个一键三连哦!谢谢大家了!!


    有缘人才可以看得到的哦!!!

    点击访问!小编自己的网站,里面也是有很多好的文章哦!

  • 相关阅读:
    uniapp easycom
    使用redis pipeline提升性能
    人工智能在日常生活中的应用
    机器学习3-岭回归,Lasso,变量选择技术
    亮相“外滩金融峰会” 百望云实力入选“融城杯金融科技创新十佳案例”
    华为机试 - 模拟商场优惠打折
    NIO原理浅析(二)
    CAD新手必练图形三
    Java实现double类型数据取小数点位数
    艾美捷FcyRl (CD64),FCGR1A,生物活性活动分析结果
  • 原文地址:https://blog.csdn.net/qq_52423918/article/details/126856733