【Elasticsearch系列十六】Mapping 映射
1.Mapping 映射
概念:自动或手动为 index 中的_doc 建立的一种数据结构和相关配置,简称为 mapping 映射。
插入几条数据,让 es 自动为我们建立一个索引
PUT /website/_doc/1
{
"post_date": "2019-01-01",
"title": "my first article",
"content": "this is my first article in this website",
"author_id": 11400
}
PUT /website/_doc/2
{
"post_date": "2019-01-02",
"title": "my second article",
"content": "this is my second article in this website",
"author_id": 11400
}
PUT /website/_doc/3
{
"post_date": "2019-01-03",
"title": "my third article",
"content": "this is my third article in this website",
"author_id": 11400
}
对比数据库建表语句
create table website(
post_date date,
title varchar(50),
content varchar(100),
author_id int(11)
);
动态映射:dynamic mapping,自动为我们建立 index,以及对应的 mapping,mapping 中包含了每个 field 对应的数据类型,以及如何分词等设置。
重点:我们当然,也可以手动在创建数据之前,先创建 index,以及对应的 mapping
GET /website/_mapping/
{
"website" : {
"mappings" : {
"properties" : {
"author_id" : {
"type" : "long"
},
"content" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"post_date" : {
"type" : "date"
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
尝试各种搜索
GET /website/_search?q=2019 0条结果
GET /website/_search?q=2019-01-01 1条结果
GET /website/_search?q=post_date:2019-01-01 1条结果
GET /website/_search?q=post_date:2019 0 条结果
搜索结果为什么不一致,因为 es 自动建立 mapping 的时候,设置了不同的 field 不同的 data type。不同的 data type 的分词、搜索等行为是不一样的。
2.精确匹配与全文搜索
exact value 精确匹配:
2019-01-01,exact value,搜索的时候,必须输入 2019-01-01,才能搜索出来
如果你输入一个 01,是搜索不出来的 select * from book where name= ‘java’
full text 全文检索:
搜“笔记电脑”,笔记本电脑词条也要搜索出来,是如何做到的呢?
select * from book where name like ‘%java%’
-
缩写 vs. 全称:cn vs. china
-
格式转化:like liked likes
-
大小写:Tom vs tom
-
同义词:like vs love
不是单纯的只是匹配完整的一个值,而是可以对值进行拆分词语后(分词)进行匹配,也可以通过缩写、时态、大小写、同义词等进行匹配。
3.倒排索引核心原理
计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引
,指明该词在文章中出现的次数和位置
,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这种建立索引的方式叫倒排索引。
当数据写入 ES 时,数据将会通过分词被切分为不同的 term,ES 将 term 与其对应的文档列表建立一种映射关系,这种结构就是倒排索引。如下图所示
为了进一步提升索引的效率,ES
在 term
的基础上利用 term
的前缀或者后缀构建了term index
, 用于对 term
本身进行索引,ES
实际的索引结构如下图所示:
这样当我们去搜索某个关键词时,ES
首先根据它的前缀
或者后缀
迅速缩小关键词的在 term dictionary
中的范围,大大减少了磁盘IO的次数
。
举例
doc1:I really liked my small dogs, and I think my mom also liked them.
doc2:He never liked any dogs, so I hope that my mom will not expect me to liked him.
分词,初步的倒排索引的建立
term | doc1 | doc2 |
---|---|---|
I | * | * |
really | * | |
liked | * | * |
my | * | * |
small | * | |
dogs | * | |
and | * | |
think | * | |
mom | * | * |
also | * | |
them | * | |
He | * | |
never | * | |
any | * | |
so | * | |
hope | * | |
that | * | |
will | * | |
not | * | |
expect | * | |
me | * | |
to | * | |
him | * |
演示了一下倒排索引最简单的建立的一个过程
mother like little dog,不可能有任何结果
这不是我们想要的结果。同义词 mom\mother 在我们人类看来是一样。想进行标准化操作。
重建倒排索引:
normalization 正规化,建立倒排索引的时候,会执行一个操作,也就是说对拆分出的各个单词进行相应的处理,以提升后面搜索的时候能够搜索到相关联的文档的概率
时态的转换,单复数的转换,同义词的转换,大小写的转换
-
mom ―> mother
-
liked ―> like
-
small ―> little
-
dogs ―> dog
重新建立倒排索引,加入 normalization,再次用 mother liked little dog 搜索,就可以搜索到了
word | doc1 | doc2 | normalization |
---|---|---|---|
I | * | * | |
really | * | ||
like | * | * | liked ―> like |
my | * | * | |
little | * | small ―> little | |
dog | * | dogs ―> dog | |
and | * | ||
think | * | ||
mother | * | * | mom ―> mother |
also | * | ||
them | * | ||
He | * | ||
never | * | ||
any | * | ||
so | * | ||
hope | * | ||
that | * | ||
will | * | ||
not | * | ||
expect | * | ||
me | * | ||
to | * | ||
him | * |
重新搜索
搜索:mother liked little dog
对搜索条件经行分词 normalization
mother
liked -》like
little
dog
doc1 和 doc2 都会搜索出来
4.分词器 analyzer
作用:
- 切分词语
- normalization
- 提升 recall 召回率
analyzer:
给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单词进行 normalization(时态转换,单复数转换)
recall召回率:
搜索的时候,增加能够搜索到的结果的数量
analyzer 组成部分:
- character filter:在一段文本进行分词之前,先进行预处理,比如说最常见的就是,过滤 html 标签
- tokenizer:分词,hello you and me --> hello, you, and, me
- token filter:
- lowercase
- stop word: a/the/an --> 干掉
- synonymom
- dogs --> dog 单复数
- liked --> like 时态
- Tom --> tom 大小写
- mother --> mom 近义词
- small --> little 近义词
一个分词器,将一段文本进行各种处理,最后处理好的结果才会拿去建立倒排索引。
5.内置分词器
例句:Set the shape to semi-transparent by calling set_trans(5)
-
standard analyzer 标准分词器:set, the, shape, to, semi, transparent, by, calling, set_trans, 5(默认的是 standard)
-
simple analyzer 简单分词器:set, the, shape, to, semi, transparent, by, calling, set, trans
-
whitespace analyzer:Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
-
language analyzer(特定的语言的分词器,比如说,english,英语分词器):set, shape, semi, transpar, call, set_tran, 5
6.根据字段分词策略
query string 必须以和 index 建立时相同的 analyzer 进行分词
query string 对 exact value 和 full text 的区别对待
-
date:exact value 精确匹配
-
text: full text 全文检索
#测试分词器
GET /_analyze
{
"analyzer": "standard",
"text": "Text to analyze 80"
}
返回值:
{
"tokens": [
{
"token": "text",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "to",
"start_offset": 5,
"end_offset": 7,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "analyze",
"start_offset": 8,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "80",
"start_offset": 16,
"end_offset": 18,
"type": "<NUM>",
"position": 3
}
]
}
-
token 实际存储的 term 关键字
-
position 在此词条在原文本中的位置
-
start_offset/end_offset 字符在原始字符串中的位置
7.mapping 总结
-
往 es 里面直接插入数据,es 会自动建立索引,同时建立对应的 mapping。(dynamic mapping)
-
mapping 中就自动定义了每个 field 的数据类型
-
不同的数据类型(比如说 text 和 date),可能有的是 exact value,有的是 full text
-
exact value,在建立倒排索引的时候,分词的时候,是将整个值一起作为一个关键词建立到倒排索引中的;full text,会经历各种各样的处理,分词,normaliztion(时态转换,同义词转换,大小写转换),才会建立到倒排索引中。
-
同时呢,exact value 和 full text 类型的 field 就决定了,在一个搜索过来的时候,对 exact value field 或者是 full text field 进行搜索的行为也是不一样的,会跟建立倒排索引的行为保持一致;比如说 exact value 搜索的时候,就是直接按照整个值进行匹配,full text query string,也会进行分词和 normalization 再去倒排索引中去搜索
-
可以用 es 的 dynamic mapping,让其自动建立 mapping,包括自动设置数据类型;也可以提前手动创建 index 和 tmapping,自己对各个 field 进行设置,包括数据类型,包括索引行为,包括分词器,等。
8.核心的数据类型
类型 | 说明 |
---|---|
string | text and keyword |
Numeric | long, integer, short, byte, double, float, half_float, scaled_float |
Date | date |
Date nanoseconds | date_nanos |
Boolean | boolean |
Binary | binary |
Range | integer_range, float_range, long_range, double_range, date_range |
dynamic mapping 推测规则:
-
true or false --> boolean
-
123 --> long
-
123.45 --> double
-
2019-01-01 --> date
-
“hello world” --> text/keywod
查看 mapping:
GET /index/_mapping/
9.手动管理 mapping
查询所有索引的映射:
GET /_mapping
创建映射:
创建索引后,应该立即手动创建映射
PUT book/_mapping
{
"properties": {
"name": {
"type": "text"
},
"description": {
"type": "text",
"analyzer":"english",
"search_analyzer":"english"
},
"pic":{
"type":"text",
"index":false
},
"studymodel":{
"type":"text"
}
}
}
10.Text 文本类型
analyzer:
通过 analyzer 属性指定分词器。
上边指定了 analyzer 是指在创建索引和搜索时都使用 english,如果单独想定义搜索时使用的分词器则可以通过 search_analyzer 属性。
index:
index 属性指定是否索引。默认为 index=true,即要进行索引,只有进行索引才可以从索引库搜索到。
但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将 index 设置为 false。
删除索引,重新创建映射,将 pic 的 index 设置为 false,尝试根据 pic 去搜索,结果搜索不到数据。
store:
是否在 source 之外存储,每个文档索引后会在 ES 中保存一份原始文档,存放在"_source"中,一般情况下不需要设置 store 为 true,因为在_source 中已经有一份原始文档了。
测试
PUT book/_mapping
{
"properties": {
"name": {
"type": "text"
},
"description": {
"type": "text",
"analyzer":"english",
"search_analyzer":"english"
},
"pic":{
"type":"text",
"index":false
},
"studymodel":{
"type":"text"
}
}
}
插入文档:
PUT /book/_doc/1
{
"name":"Bootstrap开发框架",
"description":"Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的精美界面效果。",
"pic":"group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
"studymodel":"201002"
}
Get /book/_search?q=name:开发
Get /book/_search?q=description:开发
Get /book/_search?q=pic:group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg
Get /book/_search?q=studymodel:201002
通过测试发现:name 和 description 都支持全文检索,pic 不可作为查询条件。
11.keyword 关键字
目前已经取代了"index": false。
上边介绍的 text 文本字段在映射时要设置分词器,keyword 字段为关键字字段,通常搜索 keyword 是按照整体搜索,所以创建 keyword 字段的索引时是不进行分词的,比如:邮政编码、手机号码、身份证等。
keyword 字段通常用于过虑、排序、聚合等。
12.date 日期类型
日期类型不用设置分词器。通常日期类型的字段用于排序。
format:
通过 format 设置日期格式
下边的设置允许 date 字段存储年月日时分秒、年月日格式。
{
"properties": {
"timestamp": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
}
}
}
插入文档:
Post book/doc/3
{
"name": "spring 开发基础",
"description": "spring 在 java 领域非常流行,java 程序员都在用。",
"studymodel": "201001",
"pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
"timestamp": "2018-07-04 18:28:58"
}
13.数值类型
1、尽量选择范围小的类型,提高搜索效率
2、对于浮点数尽量用比例因子
,比如一个价格字段,单位为元,我们将比例因子设置为 100 这在 ES 中会按分 存储,映射如下:
"price": {
"type": "scaled_float",
"scaling_factor": 100
},
由于比例因子为 100,如果我们输入的价格是 23.45 则 ES 中会将 23.45 乘以 100 存储在 ES 中。
如果输入的价格是 23.456,ES 会将 23.456 乘以 100 再取一个接近原始值的数,得出 2346。
使用比例因子的好处是整型比浮点型更易压缩,节省磁盘空间。
更新已有映射,并插入文档:
PUT book/doc/3
{
"name": "spring开发基础",
"description": "spring 在java领域非常流行,java程序员都在用。",
"studymodel": "201001",
"pic":"group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
"timestamp":"2018-07-04 18:28:58",
"price":38.6
}
14.修改映射
只能创建 index 时手动建立 mapping,或者新增 field mapping,但是不能 update field mapping。
因为已有数据按照映射早已分词存储好。如果修改,那这些存量数据怎么办。
删除映射:
通过删除索引来删除映射。
新增一个字段 mapping
PUT /book/_mapping/
{
"properties": {
"new_field": {
"type": "text",
"index": "false"
}
}
}
如果修改 mapping,会报错
PUT /book/_mapping/
{
"properties": {
"studymodel": {
"type": "keyword"
}
}
}
返回:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
}
],
"type": "illegal_argument_exception",
"reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
},
"status": 400
}
15.复杂数据类型
multivalue field:
{
"tags": ["tag1", "tag2"]
}
建立索引时与 string 是一样的,数据类型不能混
empty field:
null,[],[null]
object field:
PUT /company/_doc/1
{
"address": {
"country": "china",
"province": "guangdong",
"city": "guangzhou"
},
"name": "jack",
"age": 27,
"join_date": "2019-01-01"
}
address:object 类型
查询映射
GET /company/_mapping
{
"company" : {
"mappings" : {
"properties" : {
"address" : {
"properties" : {
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"country" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"province" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"age" : {
"type" : "long"
},
"join_date" : {
"type" : "date"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
object
{
"address": {
"country": "china",
"province": "guangdong",
"city": "guangzhou"
},
"name": "jack",
"age": 27,
"join_date": "2017-01-01"
}
底层存储格式
{
"name": [jack],
"age": [27],
"join_date": [2017-01-01],
"address.country": [china],
"address.province": [guangdong],
"address.city": [guangzhou]
}
对象数组:
{
"authors": [
{ "age": 26, "name": "Jack White" },
{ "age": 55, "name": "Tom Jones" },
{ "age": 39, "name": "Kitty Smith" }
]
}
存储格式:
{
"authors.age": [26, 55, 39],
"authors.name": [jack, white, tom, jones, kitty, smith]
}
Elasticsearch 的使用场景包括:
- 应用搜索:为网站或应用程序提供搜索功能,如电商、社交媒体等。
- 日志记录和日志分析:收集、存储和分析服务器日志、应用日志等。
- 基础设施监控:监控服务器、网络设备等基础设施的性能指标。
- 安全分析:分析安全日志,进行入侵检测和威胁分析。
- 地理位置数据分析:处理地理空间数据,提供地理位置搜索服务。
- 商业智能:对商业数据进行分析,提供决策支持。
Elasticsearch 的引入主要是为了应对大数据环境下的海量数据检索和实时分析需求,它通过分布式架构和高效的索引机制,提供了快速的搜索和分析能力。然而,Elasticsearch 也存在一些潜在风险,如响应时间问题和任务恢复延迟等,需要通过优化配置和维护来降低这些风险的影响。
- 点赞
- 收藏
- 关注作者
评论(0)