美文网首页
Elasticsearch学习笔记(11) - Mapping及

Elasticsearch学习笔记(11) - Mapping及

作者: juconcurrent | 来源:发表于2019-08-02 09:30 被阅读0次

    Elasticsearch的Mapping,定义了索引的结构,类似于关系型数据库的Schema。Elasticsearch的Setting主要是为了定义搜索的最关键组件,即:Analyzer,也就是分析器。

    Dynamic Mapping及常用字段类型

    Mapping的定义

    Mapping类似于关系型数据库的Schema,主要包含以下内容:

    1. 定义索引中字段的名称
    2. 定义字段的数据类型,如:字符串、数字、boolean等
    3. 可对字段设置倒排索引的相关配置,如是否需要分词,使用什么分词器

    从7.x开始,一个Mapping只属于一个索引的type

    1. 每个文档属于一个type
    2. 一个type有且仅有一个Mapping定义
    3. 从7.x开始,不需要在Mapping中指定type信息,默认type为_doc

    常用字段类型

    在Elasticsearch中,字段数据类型有以下常用的类型:

    1. 简单类型
      • Text / Keyword - 文本 / 关键字
      • Date - 日期
      • Integer / Float - 数字 / 浮点
      • Boolean - 布尔值
      • IPv4 / IPv6 - ip地址
    2. 复杂类型,包括对象和数组
      • 对象
      • 数组
    3. 特殊类型,如地理信息
      • geo_point / ...

    动态Mapping

    动态Mapping,英文名为Dynamic Mapping。

    1. 在写入文档时,如果索引不存在,会自动创建索引
    2. 这种机制,使得我们无需手动定义mappings。Elasticsearch会自动根据文档信息,推算出字段的类型
    3. 有的时候,Elasticsearch可能会推算不对,如:地理位置信息
    4. 当类型推算得不对时,可能导致一些功能无法正常运行,如Range查询。

    常用类型的自动识别规则

    类型 规则
    字符串 匹配到日期格式,设置成Date。
    字符串为数字时,当成字符串处理,但我们设置转换为数字。
    其他情况,类型就是Text,并且会增加keyword的子字段
    布尔值 Boolean
    浮点数 Float
    整数 Long
    对象 Object
    数组 由第一个非空数值的类型决定
    空值 忽略
    # 写入文档,查看 Mapping
    PUT mapping_test/_doc/1
    {
      "firstName": "Chan", -- Text
      "lastName":  "Jackie", -- Text
      "loginDate": "2018-07-24T10:29:48.103Z" -- Date
    }
    
    # Dynamic Mapping,推断字段的类型
    PUT mapping_test/_doc/1
    {
        "uid": "123", -- Text
        "isVip": false, -- Boolean
        "isAdmin": "true", -- Text
        "age": 19, -- Long
        "heigh": 180 -- Long
    }
    
    # 查看 Dynamic Mapping
    GET mapping_test/_mapping
    

    字段类型是否可修改

    1. 新增加的字段
      • dynamic设为true时,新增字段的文档写入时,Mapping同时被更新
      • dynamic设为false时,Mapping不会被更新,新增字段的数据无法被索引,但是会出现在_source中
      • dynamic设为strict,文档将写入失败
    2. 已存在的字段,一旦数据被写入,就不再支持修改字段定义
      • Lucene本身的限制
    3. 如果希望更改字段类型,必须Reindex api,即:重建索引。在数据量多的时候,开销将非常大
    # dynamic设置为false
    PUT idx1
    {
        "mapping": {
            "_doc": {
                "dynamic": "false"
            }
        }
    }
    
    # 修改为dynamic为false
    PUT idx1/_mapping
    {
      "dynamic": false
    }
    
    # 查看索引
    GET idx1/_mapping
    

    dynamic属性和索引字段可变性的规则,我们可以总结如下:

    \ true false strict
    文档可索引 yes yes no
    字段可索引 yes no no
    Mapping被更新 yes no no

    显式Mapping及常见参数

    在本文的上一段落,我们的Mapping都是自动生成的。自动生成机制虽然方便,但是也可能导致一些问题。比如:生成的字段类型不正确,字段的附加属性不满足我们的需求,等等。这时,我们可以通过显式Mapping的方式来解决。

    那么,我们如何进行显式Mapping的设置呢?

    1. 参考官网api,纯手写
    2. 为减少工作量,减少出错概率,可如下进行:
      1. 创建一个临时index,写入一些样本数据
      2. 通过访问Mapping API获取该临时文件的动态Mapping定义
      3. 修改后,再使用此配置创建自己的索引
      4. 删除临时索引

    我们推荐使用第二种方式,效率高,且不容易出错。

    常见参数 - index

    index,可用于设置字段是否被索引,默认为true,false即为不可搜索。在下述例子中,mobile字段将不能被搜索到。

    # 设置 index 为 false
    DELETE users
    PUT users
    {
        "mappings" : {
          "properties" : {
            "firstName" : {
              "type" : "text"
            },
            "lastName" : {
              "type" : "text"
            },
            "mobile" : {
              "type" : "text",
              "index": false
            }
          }
        }
    }
    

    常见参数 - index_options

    记录索引级别。Text类型默认为positions,其他类型默认为docs。我们需要记住一条准则。

    记录的内容越多,占用的存储空间就越大。

    索引级别有以下几种,更细节的内容可参考【官网索引级别】

    1. docs
    2. freqs
    3. positions
    4. offsets

    常见参数 - null_value

    需要对Null值实现搜索时使用。只有keyword类型才支持设定null_value

    # 设定Null_value
    DELETE users
    PUT users
    {
        "mappings" : {
          "properties" : {
            "firstName" : {
              "type" : "text"
            },
            "lastName" : {
              "type" : "text"
            },
            "mobile" : {
              "type" : "keyword",
              "null_value": "NULL"
            }
          }
        }
    }
    
    PUT users/_doc/1
    {
      "firstName":"Zhang",
      "lastName": "Fubing",
      "mobile": null
    }
    
    PUT users/_doc/2
    {
      "firstName":"Zhang",
      "lastName": "Fubing2"
    }
    
    # 查看结果,有且仅有_id为2的记录
    GET users/_search
    {
      "query": {
        "match": {
          "mobile":"NULL"
        }
      }
    }
    

    常见参数 - copy_to

    这个属性用于将当前字段拷贝到指定字段。

    1. _all在7.x版本已经被copy_to所代替
    2. 可用于满足特定场景
    3. copy_to将字段数值拷贝到目标字段,实现类似_all的作用
    4. copy_to的目标字段不出现在_source中
    # 设置 Copy to
    DELETE users
    PUT users
    {
      "mappings": {
        "properties": {
          "firstName":{
            "type": "text",
            "copy_to": "fullName"
          },
          "lastName":{
            "type": "text",
            "copy_to": "fullName"
          }
        }
      }
    }
    PUT users/_doc/1
    {
      "firstName":"Zhang",
      "lastName": "Fubing"
    }
    
    GET users/_search?q=fullName:(Zhang Fubing)
    

    特殊的数组类型

    Elasticsearch不提供专门的数组类型。但任何字段,都可以包含多个相同类型的数值。

    # 数组类型
    PUT users/_doc/1
    {
      "name":"onebird",
      "interests":"reading"
    }
    
    PUT users/_doc/1
    {
      "name":"twobirds",
      "interests":["reading","music"]
    }
    
    POST users/_search
    {
      "query": {
            "match_all": {}
        }
    }
    
    # interests字段还是text类型
    GET users/_mapping
    

    多字段类型及自定义Analyzer

    多字段类型

    所谓多字段类型,即:一个字段可以有多个子字段。这种特性带来了以下好处。

    1. 增加一个keyword子字段,可用于精确匹配
    2. 可对子字段设置不同的analyzer
      1. 不通语言的支持
      2. 可对中文拼音字段进行搜索
      3. 可对搜索和索引指定不同的Analyzer

    精确值和全文本

    精确值(Exact Values) vs 全文本(Full Text)

    1. 精确值,包括数字、日期、具体的字符串(如“192.168.0.1”)
      • Elasticsearch中类型为keyword,索引时,不需要做特殊的分词处理
    2. 全文本,非结构化的文本数据
      • Elasticsearch中类型为text,索引时,需要对其进行分词处理

    如下结构的数据,我们可以大致判断出哪些是精确值,哪些是全文本。其中的200、info、debug都是精确值。而message的内容为全文本。

    {
        "code": 200,
        "message": "this is a error item, you can change your apollo config !",
        "content": {
            "tags": [
                "info",
                "debug"
            ]
        }
    }
    

    自定义分词器

    自定义分词器,可通过组合不同的Character FilterTokenizerToken Filter来实现。

    Character Filter,常用的字符过滤器包括:

    类型 作用
    html strip 去除html
    mapping 字符串替换
    pattern replace 正则匹配替换

    Tokenizer,用于将原始文本按照一定规则切分为词(Term或Token)。我们除了使用Elasticsearch自动的分词器外,还可以自己通过开发插件的方式来实现。常用的分词器包括:

    • whitespace
    • standard
    • uax_url_email
    • pattern
    • keyword
    • path
    • hierarchy

    Token Filter,分词过滤器。主要用于对输出的单词,进行增删改。常用的分词过滤器包括:

    类型 作用
    lowercase 转换为小写
    stop 去掉the、a、an等单词
    synonym 转换为近义词

    在下面的例子中,我们实现了一个自定义分词器。

    # 编写自定义分析器
    PUT index1
    {
        "settings": {
            "analysis": {
                "analyzer": {
                    "my_custom_analyzer": {
                        "type": "custom",
                        "char_filter": ["emoticons"],
                        "tokenizer": "punctuation",
                        "filter": [
                            "lowercase",
                            "english_stop"
                        ]
                    }
                },
                "tokenizer": {
                    "punctuation": {
                        "type":"pattern",
                        "pattern": "[ .,!?]"
                    }
                },
                "char_filter": {
                    "emoticons": {
                        "type": "mapping",
                        "mappings": [
                            ":) => _happy_",
                            ":( => _sad_"
                        ]
                    }
                },
                "filter": {
                    "english_stop": {
                        "type": "stop",
                        "stopwords": "_english_"
                    }
                }
            }
        }
    }
    
    # 查看自定义分析器的效果
    POST index1/_analyze
    {
        "analyzer": "my_custom_analyzer",
        "text": "I'm a :) person, and you?"
    }
    

    总结

    通过这篇文章,我们了解了Mapping的作用及常用字段类型,也知道了动态Mapping和显式Mapping的区别。另外,我们还了解了Mapping的多字段特性,以及如何自定义一个Analyzer。

    相关文章

      网友评论

          本文标题:Elasticsearch学习笔记(11) - Mapping及

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