前言
掘友们好久不见,在之前的文章中,我们了解到了elasticsearch的查找相关操作方法和一些原理,本章节将带来elasticsearch的mapping详细配置和用法,主要分为
- dynamic mapping机制
- 显示mapping和相关参数
- 多字段特性及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+/
的快捷键,可以快速查看官网的文档,互相结合,理解效率更高。
觉得不错,请点个赞吧