Elasticsearch入门(3)-mapping

掘友们好久不见,在之前的文章中,我们了解到了elasticsearch的查找相关操作方法和一些原理,本章节将带来elasticsearch的mapping详细配置和用法,主要分为

    1. dynamic mapping机制
    1. 显示mapping和相关参数
    1. 多字段特性及mapping中自定义analyzer

Dynamic mapping

mapping

mapping类似于数据库中的schema的定义,作用如下

定义索引中的字段的名称

定义字段的数据类型,例如字符串,数字,布尔

字段,倒排索引的相关配置(Analyzed or Not Analyzed,Analyzer)

Mapping会把JSON文档映射成Lucene所需要的扁平格式

一个Mapping属于一个索引的Type

每个文档都属于一个Type

一个Type有一个Mapping定义

7.0开始,不需要在Mapping定义中指定Type信息

1. 是什幺

在写入文档时候,如果索引不存在,会自动创建索引

Dynamic Mapping的机制,使得我们无需手动定义Mappings.Elasticsearch会根据文档信息,推算出字段的类型

会遇到推算的不对的情况,例如地理位置信息

当类型设置不对时,会导致一些功能无法正常运行,例如Range查询

# 查看Mapping,get ${indexname}/_mappings
GET movies/_mappings

2. 类型的自动识别

JSON类型 Elasticsearch
字符串 匹配成日期格式,设置成Date
配置数字设置为float或long,该选项默认关闭
设置为text,并且增加keyword子字段
布尔值 boolean
浮点数 float
整数 long
对象 Object
数组 由第一个非空数值的类型所决定
空值 忽略

demo

# dynamic mapping 推断字段的类型
PUT mapping_test/_doc/1
{
  "uid":"123",
  "isVip":false,
  "isAdmin":"true",
  "age":19,
  "height":"183"
}
# 查看Mapping文件,查看mapping推算
GET mapping_test/_mapping

查看结果如图,我们可以发现es对输入的json进行了相应的类型转换

3. 更改Mapping的字段类型

两种情况下能够修改

新增加字段

Dynamic 设置为true时,一旦有新增字段的文档写入,Mapping也同时被更新

Dynamic设为false,当有新的文档加入,并且新的文档包含新的字段,Mapping不会被更新,意味着新增字段的数据无法被索引,但是信息会出现在_source中

Dynamic设置为Strict,文档写入失败

对已有字段,一旦已有数据写入,就不再支持修改字段定义

es基于Lucene实现的倒排索引,一旦生成后,就不允许修改

如果希望改变字段类型,必须Reindex API,重建索引

原因

如果修改了字段的数据类型,会导致已被索引的属于无法被搜索

对于新增字段,不存在该影响(新增字段时建立新字段索引)

4. 控制Dynamic mappings

dynamic设置对应功能

“true” “false” “strict”
文档可索引 ×
字段可索引 × ×
Mapping被更新 × ×

当dynamic被设置为false时候,存在新增字段的数据写入,该数据可以被索引,但是新增字段被丢弃

当设置为Strict模式时候,数据写入直接出错

4.1 true

文档可索引,字段可索引,mapping被更新

# 默认mapping支持dynamic,写入的文档中加入新的字段
PUT dynamic_mapping_test/_doc/1
{
  "newFileld":"someValue" 
}
# 搜索
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "newFileld": "someValue"
    }
  }
}
GET dynamic_mapping_test/_mapping

4.2 false

文档可索引,字段不可索引,mapping不更新

# 修改dynamic false
PUT dynamic_mapping_test/_mapping
{
  "dynamic":"false"
}
# 新增 anotherField
PUT dynamic_mapping_test/_doc/2
{
  "anotherField":"anotherValue"
}
# 新增的字段不可以被搜索,因为dynamic已经被设置为false
POST dynamic_mapping_test/_search
{
  "query": {
    "match": {
      "anotherField": "anotherValue"
    }
  }
}

# mapping文件查询
GET dynamic_mapping_test/_mapping

4.3 strict

文档不可索引,字段不可索引,mapping不更新

# 修改为strict
PUT dynamic_mapping_test/_mapping
{
  "dynamic":"strict"
}
# 写入数据,http code 400
PUT dynamic_mapping_test/_doc/3
{
  "lastField":"lastValue"
}

显示mapping和参数介绍

1. 如何显示定义

PUT docName
{
    “mapping”:{
        # define your mapping here
    }
}

2. 自定义mapping的建议

可以参考API手册,纯手写

为了减少输入的工作量,减少出错概率,可以依照以下步骤

创建一个临时的index,写入一些样本数据

通过访问Mapping API获得该临时文件的动态Mapping定义

修改后使用,参考该配置创建自己的索引

删除临时索引

3. index

Index属性:控制当前字段是否被索引,默认为true,如果设置为false,字段不可被索引

PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text"
      },
      "lastName":{
        "type":"text"
      },
      "mobile":{
        "type":"text",
        "index":false
      }
    }
  }
}

4. Index Options

对于倒排索引的建立,es提供了四种配置

四种不同级别的Index Options配置,可以控制倒排索引记录的内容

docs – 记录doc id

freqs – 记录doc id和term frequencies

positions – 记录doc id / term frequencies / term postion

offsets – 记录 doc id / term frequencies / term position / character offsets

Text 类型默认记录positions,其他默认为docs

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

5. null_value

有些时候插入的字段时null,如果需要对Null值实现搜素,可以在mapping文件中将“null_value”指定为“NULL”

GET users/_search?q=mobile:NULL
PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text"
      },
      "lastName":{
        "type":"text"
      },
      "mobile":{
        "type":"keyword",
        "null_value": "NULL"
      }
    }
  }
}

注意:

只有Keyword类型支持Null_Value

6. copy_to设置

_all在es7中已被废弃,如要实现 _all 的功能,可用copy_to所替代

# 这个设定的意思就是说,你在索引一个文档时候,它如果包含了firstName和lastName,都会把值拷贝到fullName上,当需要查询的时候,就可以用fullName查询了
PUT users
{
  "mappings":{
    "properties":{
      "firstName":{
        "type":"text",
        "copy_to": "fullName"
      },
      "lastName":{
        "type":"text",
        "copy_to": "fullName"
      }
    }
  }
}

查询时: GET users/_search?q=fullName:(Jack Ma)

特点:

能满足一些特定的搜索需求

copy_to将字段的数值拷贝到目标字段,实现类似_all的作用

copy_to的目标字段不出现在_source中

7. 数组类型

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

PUT users/_doc/1
{
    "name":"zhangsan",
    "interests":"reading"
}
PUT users/_doc/2
{
    "name":"lisi",
    "interests":["reading","coding"]
}

查看mapping文件,可发现interests类型依然是text

多字段特性及Mapping中配置自定义Analyzer

1. 多字段类型

比如一个默认的text字段,es都会给它加上keyword字段类型,但有时候会给特定字段加上子字段,指定analyzer

多字段特性

厂商名字实现精确匹配

增加一个keyword字段

使用不同的Analyzer

不同语音

拼音字段的搜索

支持为搜索和索引指定不同的analyzer

2. Exact value v.s Full Text

Exact value

精确值,包括数据/日期/具体的一个字符串(例如“Apple Store”)

Elasticsearch中的keyword

Full Text

全文本,非结构化的文本数据

Elasticsearch中的text

如图,exact value箭头标注的值,对待这种数值,很多情况下我们要将这种数值作为精确值来看待,不需要对它进行分词。

但消息中的message需要对它进行分词处理,以查到一些关键词

2.1 Exact Values不需要被分词

在elasticsearch中,exact value不需要做分词处理

Elasticsearch为每一个字段创建一个倒排索引

Exact Value在索引时,不需要做特殊的分词处理

3. 自定义分词

当Elasticsearch自带的分词器无法满足时,可以自定义分词器,通过自组合不同的组件实现

Character Filter

Tokenizer

Token Filter

3.1 Character Filter

在Tokenizer之前对文本进行处理,例如增加删除及替换字符,可以配置多个Character Filters,会影响倒排索引Tokenizer的positon和offset信息

一些自带的Character Filters

HTML strip – 去除html标签

#剥除不必要的html标签
POST _analyze
{
  "tokenizer": "keyword",
  "char_filter": ["html_strip"],
  "text":"<b>hello world</b>"
}

Mapping – 字符串替换

# 使用char filter进行替换,将中划线替换为下划线
POST _analyze
{
  "tokenizer": "standard",
  "char_filter": [
      {
        "type":"mapping",
        "mappings":["- => _"]
      }
    ],
    "text":"123-456, I-test! test-990 555-789-1114"
}
# char filter替换表情符号,如把表情替换为单词
POST _analyze
{
  "tokenizer": "standard",
  "char_filter": [
      {
        "type":"mapping",
        "mappings":[":) => happy",":( => sad"]
      }
    ],
    "text": ["I am felling :)","Felling :( today"]
}

Pattern replace – 正则匹配替换

# 正则方式替换,替换http
GET _analyze
{
  "tokenizer": "standard",
  "char_filter": [
      {
        "type":"pattern_replace",
        "pattern":"http://(.*)",
        "replacement":"$1"
      }
    ],
    "text": "http://www.elastic.co"
}

3.2 Tokenizer

将原始的文本按照一定的规则,切分为词(term or token)

elasticsearch内置的Tokenizers包括

whitespace/standard/uax_url_email/pattern(正则)/keyword(不做处理,直接索引)/path hierarchy(路径处理)

# tokenizer按照文件路径
POST _analyze
{
  "tokenizer": "path_hierarchy",
  "text": "/usr/jackMa/a/b/c/d/e"
}

可以用java开发插件,实现自己的Tokenizer(期待后续试验····)

3.3 Token filters

将Tokenizer输出的单词(term),进行增加,修改,删除

自带的Token Filters

Lowercase / stop / synonym(添加近义词)

# TOKEN FILTERS
# whitespace与stop,is去除
GET _analyze
{
  "tokenizer": "whitespace",
  "filter": ["stop"],
  "text": ["The stone is knocked"]
}

# remove 加入lowercase后,小写处理,然后The被当成stopword删除
GET _analyze
{
  "tokenizer": "whitespace",
  "filter": ["lowercase","stop"],
  "text": ["The man sitting on the Chair is my classmate!"]
}

3.4 设置一个custom Analyzer

创建索引时,定义custom Analyzer

#如何自定义Analyzer
# 先删除之前创建的
DELETE my_index
# 可以在创建索引的时候指定setting,首先我们定义分词器,其中的char_filter和tokenizer还有filter中的English_stop都是自定义的
PUT my_index
{
  "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_"
        }
      }
    }
  }
}

针对创建的analyzer进行测试

# 测试自定义的analyzer
POST my_index/_analyze
{
  "analyzer": "my_custom_analyzer",
  "text":"I'm a :) person, and you?"
}

分词结果:

3.4.1 方法论

自定义分析器标准格式是:

PUT /my_index
{
    "settings": {
        "analysis": {
            "char_filter": { ... custom character filters ... },//字符过滤器
            "tokenizer": { ... custom tokenizers ... },//分词器
            "filter": { ... custom token filters ... }, //词单元过滤器
            "analyzer": { ... custom analyzers ... }
        }
    }
}

实例:

PUT /my_index
{
    "settings": {
        "analysis": {
            "char_filter": {
                "&_to_and": {
                    "type": "mapping",
                    "mappings": [ "&=> and "]
            }},
            "filter": {
                "my_stopwords": {
                    "type": "stop",
                    "stopwords": [ "the", "a" ]
            }},
            "analyzer": {
                "my_analyzer": {
                    "type": "custom",
                    "char_filter": [ "html_strip", "&_to_and" ],
                    "tokenizer": "standard",
                    "filter": [ "lowercase", "my_stopwords" ]
            }}
}}}
# 比如自定义好的analyzer名字是my_analyzer,在此索引下的某个新增字段应用此分析器
PUT /my_index/_mapping
{
   "properties":{
        "username":{
             "type":"text",
              "analyzer" : "my_analyzer"
         },
        "password" : {
          "type" : "text"
        }
    
  }
}
# 插入数据
PUT /my_index/_doc/1
{
  "username":"The quick & brown fox ",
   "password":"The quick & brown fox "

}
# username采用自定义分析器my_analyzer,password采用默认的standard分析器
# 验证
GET /index_v1/_analyze
{
  "field":"username",
  "text":"The quick & brown fox"
}
GET /index_v1/_analyze
{
  "field":"password",
  "text":"The quick & brown fox"
}

小结

本篇对elasticsearch的mapping机制进行了大篇幅的介绍和讲解,具体的代码部分不用死机硬背,再实际操练时候,结合 Ctrl+/ 的快捷键,可以快速查看官网的文档,互相结合,理解效率更高。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章