zoukankan      html  css  js  c++  java
  • 使用normalizer优化keyword字段的查询

    我们知道elasticsearch提供了很多的字段类型,当我们索引结构化的简单字段的时候可以使用keyword类型,例如id,email、主机名、状态码、标签、邮政编码等;

    但是keyword字段类型在索引的时候,并不会对字段的值进行一些预处理,也就是直接保留字段的原值。

    当我们使用如下文档进行索引的时候,es到底是怎样进行索引处理的呢?

     {
        "id":1,
        "name":"code"
    }

     Es字段的索引是通过对应类型的mapper进行处理,通过KeywordFieldMapper的parseCreateField的396行可以看到索引的时候,es直接将name字段的value即”code”作为二进制保存,没有进行任何的处理。 

    当我使用如下的查询语句进行查询的时候,es是怎么来构建查询语句的呢?

    {
        "query":{
            "term":{
                "name":"code"
            }
        }
    }

    Es首先会获取name字段对应的字段类型,然后调用字段的termQuery来构建查询语句;

    这里name字段对应的是KeywordFieldMapper,其并没有覆盖实现父类的的termQuery方法,所以直接执行父类TermBasedFieldType的对应方法,方法中使用indexedValueForSearch对查询关键字进行处理;

    我们可以看到KeywordFieldMapper实现了indexedValueForSearch, 由于初始化的时候将search/index的Analyzer都设置为Lucene.KEYWORD_ANALYZER,所以这里会执行305行调用父类TermBasedFieldType的indexedValueForSearch。

    我们可以看到父类TermBasedFieldType也未对value进行任何的处理;

    这样会带来一个问题,如果字段对应的值并不是枚举类型,而是用户输入的标签等,如果用户输入的单词包含大小写,那么搜索的时候也必须输入一模一样的关键字,否则使用下边的查询语句是命中不了结果的;

    {
        "query":{
            "term":{
                "name":"Code"
            }
        }
    }

    通过查询es的文档,我们可以看到keyword类型提供了一个normalizer的配置参数,可以在index之前进行一些预处理工作;在自定义的normalizer中可以定义character filters和token filters,这样我们可以像下边这样配置一个lowercase的token filters即可以实现忽略大小写。

    {
        "settings":{
            "analysis":{
                "normalizer":{
                    "lowercase_normalizer":{
                        "type":"custom",
                        "filter":[
                            "lowercase"
                        ]
                    }
                }
            }
        },
        "mappings":{
            "_doc":{
                "properties":{
                    "id":{
                        "type":"integer"
                    },
                    "name":{
                        "type":"keyword",
                        "normalizer":"lowercase_normalizer"
                    }
                }
            }
        }

    在CustomNormalizerProvider中我们可以看到解析配置的char filters和token filters,并组合生成Custome analyzer。

    在生成name字段的mapper的时候,根据配置的normalizer name获取对象的对象,并设置为field type的normalizer和search analyzer。

    当我们index下边的文档的时候,我们看下es是怎么处理的

    {
        "id":1,
        "name":"Code"
    }

    可以看到index文档的时候,会获取keyword对应的field type的normalizer,然后对name字段的value进行处理。

    当我们搜索的时候,由于已经重置了keyword 对应的field type的searchAnalyzer,所以会直接调用新的自定的normalizer的normalize对输入的关键字进行与处理。

    最终不管我们输入的name的值大小写的形式怎样,我们都可以搜索到

  • 相关阅读:
    [转]Linux中用编译的Zlib库替换系统自带的
    [转]Leptonica在VS2010中的编译及简单使用举例
    我的tesseract学习记录
    [转]在VS2010下编译和使用tesseract_ocr
    [转]图像resize
    JVM基础知识(摘抄整理)
    JVM运行时数据内存区和指令集(摘抄整理)
    JMM For Object Size(摘抄整理)
    JMM课程小结(摘抄整理)
    Class的加载过程
  • 原文地址:https://www.cnblogs.com/wufengtinghai/p/14564318.html
Copyright © 2011-2022 走看看