ElasticSearch ( 七 ) Mapping映射和数据迁移
7.mapping 类型映射
设置查看ES索引结构
相当于 create table , 设置 数据类型
7.1.操作
7.1.1._mapping 查看索引
GET /bank/_mapping
显示 类型
{
"bank" : {
"mappings" : {
"properties" : {
"account_number" : {
"type" : "long"
},
"address" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"age" : {
"type" : "long"
},
"balance" : {
"type" : "long"
},
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"email" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"employer" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"firstname" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"gender" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"lastname" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"state" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
7.1.2.PUT 创建索引时, 声明映射
Mapping 类似于数据库中的表结构定义 schema,它有以下几个作用:
定义索引中的字段的名称定义字段的数据类型,比如字符串、数字、布尔字段,
倒排索引的相关配置,比如设置某个字段为不被索引、记录 position 等
在 ES 早期版本,一个索引下是可以有多个 Type ,从 7.0 开始,一个索引只有一个 Type,也可以说一个 Type 有一个 Mapping 定义。
定义 usermsg 索引
PUT usermsg
{
"mappings": {
"properties": {
"uid": {
"type": "long"
},
"phone": {
"type": "long"
},
"title": {
"type": "text",
"index": true ,
"analyzer": "standard",
"search_analyzer": "english"
},
"message": {
"type": "keyword"
},
"msgcode": {
"type": "integer"
},
"sendtime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
},
"_meta": {
"author": "yuan",
"version": "1.0"
},
"_source": {
"enabled": false
},
"dynamic": "strict"
}
}
7.1.3.常用属性
-
properties
: 设置属性的类型及索引 -
_meta
: 允许您存储任意元数据与映射一起。 -
_source
: 允许您控制如何存储文档源。 -
dynamic
: 定义新字段是否应该被动态添加到映射中。 -
date_detection
: 定义Elasticsearch是否自动检测日期类型字段。 -
numeric_detection
: 定义Elasticsearch是否自动检测数字类型字段。 -
dynamic_date_formats
: 如果启用了日期检测,则可以通过此选项定义要使用的格式。 -
coerce
: 是否尝试将字符串转换为数字和日期类型。 -
index
: 定义字段是否应该被索引还是只应该存储。 -
analyzer
: 定义分析器以在对字段进行全文搜索时使用。 -
search_analyzer
: 定义分析器以在执行搜索查询时使用。
7.1.3.1.dynamic
在创建一个索引的时候,可以对 dynamic 进行设置,可以设成 false、true 或者 strict。
true | false | strict | |
---|---|---|---|
文档可索引 | ✔️ | ✔️ | ✖️ |
字段可索引 | ✔️ | ✖️ | ✖️ |
Mapping被更新 | ✔️ | ✖️ | ✖️ |
比如一个新的文档,这个文档包含一个字段,
当 Dynamic 设置为 true 时,这个文档可以被索引进 ES,这个字段也可以被索引,也就是这个字段可以被搜索,Mapping 也同时被更新;
当 dynamic 被设置为 false 时候,存在新增字段的数据写入,该数据可以被索引,但是新增字段被丢弃;
当设置成 strict 模式时候,数据写入直接出错。
7.1.3.2.index
另外还有 index 参数,用来控制当前字段是否被索引,默认为 true,如果设为 false,则该字段不可被搜索。
7.1.3.3.analyzer
在这个例子中,我们使用了analyzer
和search_analyzer
参数来定义一个文本字段的分析器和搜索分析器
7.1.3.4.index_options
index_options
参数 index_options 用于控制倒排索引记录的内容,有如下 4 种配置:
- doc:只记录 doc id
- freqs:记录 doc id 和 term frequencies
- positions:记录 doc id、term frequencies 和 term position
- offsets:记录 doc id、term frequencies、term position 和 character offects
另外,text 类型默认配置为 positions,其他类型默认为 doc,记录内容越多,占用存储空间越大。
7.1.3.5.null_value
null_value 主要是当字段遇到 null 值时的处理策略,默认为 NULL,即空值,此时 ES 会默认忽略该值,可以通过设定该值设定字段的默认值,另外只有 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"
}
}
}
7.1.3.6._all
这个属性现在使用很少,不做深入讲解
参考官网:https://www.elastic.co/guide/cn/elasticsearch/guide/current/root-object.html
7.1.3.7.copy_to
这个属性用于将当前字段拷贝到指定字段。
- _all 在 7.x 版本已经被 copy_to 所代替
- 可用于满足特定场景
- copy_to 将字段数值拷贝到目标字段,实现类似_all 的作用
- copy_to 的目标字段不出现在_source 中
DELETE users
PUT users
{
"mappings": {
"properties": {
"firstName": {
"type": "text",
"copy_to": "fullName"
},
"lastName": {
"type": "text",
"copy_to": "fullName"
}
}
}
}
PUT users/_doc/1
{
"firstName": "yuan",
"lastName": "chun"
}
## 没有新建字段
GET users/_doc/1
{
"_index": "users",
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"firstName": "yuan",
"lastName": "chun"
}
}
GET users/_search?q=fullName:(yuan chun)
- first_name(名字)和 last_name(姓氏)字段复制到 full_name 字段;
- first_name(名字)和 last_name(姓氏)字段仍然可以分别查询;
- full_name 可以通过 first_name(名字)和 last_name(姓氏)来查询;
一些要点:
- 复制的是字段值,而不是 term(词条)(由分析过程产生).
- _source 字段不会被修改来显示复制的值.
- 相同的值可以复制到多个字段,通过 “copy_to”: [“field_1”, “field_2”] 来操作.
7.1.4.追加新的映射
PUT /usermsg/_mapping
{
"properties": {
"msgtype": {
"type": "keyword",
"index": false
}
}
}
7.2.类型
7.2.1.核心类型
核心类型可以划分为字符串类型、数字类型、日期类型、布尔类型、基于 BASE64 的二进制类型、范围类型。
7.2.1.1.字符串类型 text 和 keyword
其中,在 ES 7.x 有两种字符串类型:text 和 keyword,在 ES 5.x 之后 string 类型已经不再支持了。
text 类型 : 适用于需要被全文检索的字段,例如新闻正文、邮件内容等比较长的文字,text 类型会被 Lucene 分词器(Analyzer)处理为一个个词项,并使用 Lucene 倒排索引存储,text 字段不能被用于排序,如果需要使用该类型的字段只需要在定义映射时指定 JSON 中对应字段的 type 为 text。
keyword : 适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。
7.2.1.2.数字类型
数字类型分为 long、integer、short、byte、double、float、half_float、scaled_float。
数字类型的字段在满足需求的前提下应当尽量选择范围较小的数据类型,字段长度越短,搜索效率越高,对于浮点数,可以优先考虑使用 scaled_float 类型,该类型可以通过缩放因子来精确浮点数,例如 12.34 可以转换为 1234 来存储。
7.2.1.3.日期类型
date , date_nanos
在 ES 中日期可以为以下形式:
格式化的日期字符串,例如 2020-03-17 00:00、2020/03/17时间戳(和 1970-01-01 00:00:00 UTC 的差值),单位毫秒或者秒即使是格式化的日期字符串,ES 底层依然采用的是时间戳的形式存储。
7.2.1.4.布尔类型
JSON 文档中同样存在布尔类型,不过 JSON 字符串类型也可以被 ES 转换为布尔类型存储,前提是字符串的取值为 true 或者 false,布尔类型常用于检索中的过滤条件。
7.2.1.5.二进制类型
二进制类型 binary 接受 BASE64 编码的字符串,默认 store 属性为 false,并且不可以被搜索。
7.2.1.6.范围类型
范围类型可以用来表达一个数据的区间,可以分为5种:
integer_range、float_range、long_range、double_range 以及 date_range。
7.2.2.复杂类型
复合类型主要有对象类型(object)和嵌套类型(nested):
7.2.2.1.对象类型
JSON 字符串允许嵌套对象,一个文档可以嵌套多个、多层对象。可以通过对象类型来存储二级文档,不过由于 Lucene 并没有内部对象的概念,ES 会将原 JSON 文档扁平化,例如文档:
{
"name" : {
"first": "hello",
"last": "world"
}
}
实际上 ES 会将其转换为以下格式,并通过 Lucene 存储,即使 name 是 object 类型:
{
"name.first" : "hello",
"name.last" : "world"
}
7.2.2.2.嵌套类型
嵌套类型可以看成是一个特殊的对象类型,可以让对象数组独立检索,例如文档:
{
"group" : "users",
"username" : [
{ "first": "王", "last": "小二"},
{ "first": "李", "last": "小三"},
{ "first": "赵", "last": "小四"},
]
}
username 字段是一个 JSON 数组,并且每个数组对象都是一个 JSON 对象。如果将 username 设置为对象类型,那么 ES 会将其转换为:
{
"group" : "users",
"username.first" : ["王", "李", "赵"],
"username.last" : [ "小二", "小三", "小四"]
]
}
可以看出转换后的 JSON 文档中 first 和 last 的关联丢失了,如果尝试搜索 first 为"王",last 为"小三" 的文档,那么成功会检索出上述文档,但是"王"和"小三" 在原 JSON 文档中并不属于同一个 JSON 对象,应当是不匹配的,即检索不出任何结果。
嵌套类型就是为了解决这种问题的,嵌套类型将数组中的每个 JSON 对象作为独立的隐藏文档来存储,每个嵌套的对象都能够独立地被搜索,所以上述案例中虽然表面上只有 1 个文档,但实际上是存储了 4 个文档。
7.2.3.地理类型
地理类型字段分为两种:经纬度类型和地理区域类型:
7.2.3.1.经纬度类型
经纬度类型字段(geo_point)可以存储经纬度相关信息,通过地理类型的字段,可以用来实现诸如查找在指定地理区域内相关的文档、根据距离排序、根据地理位置修改评分规则等需求。
7.2.3.2.地理区域类型
经纬度类型可以表达一个点,而 geo_shape 类型可以表达一块地理区域,区域的形状可以是任意多边形,也可以是点、线、面、多点、多线、多面等几何类型。
7.2.4.特殊类型
特殊类型包括 IP 类型、过滤器类型、Join 类型、别名类型等,在这里简单介绍下 IP 类型和 Join 类型,其他特殊类型可以查看官方文档。
7.2.4.1.IP 类型
IP 类型的字段可以用来存储 IPv4 或者 IPv6 地址,如果需要存储 IP 类型的字段,需要手动定义映射:
{
"mappings":{
"properties":{
"my_ip":{
"type":"ip"
}
}
}
}
7.2.4.2.Join 类型
Join 类型是 ES 6.x 引入的类型,以取代淘汰的 _parent 元字段,用来实现文档的一对一、一对多的关系,主要用来做父子查询。
Join 类型的 Mapping 如下:
PUT my_index
{
"mappings":{
"properties":{
"my_join_field":{
"type": "join",
"relations":{
"question":"answer"
}
}
}
}
}
其中,my_join_field 为 Join 类型字段的名称;relations 指定关系:question 是 answer 的父类。
例如定义一个 ID 为 1 的父文档:
PUT my_join_index/1?refresh
{
"text": "This is a question",
"my_join_field": "question"
}
接下来定义一个子文档,该文档指定了父文档 ID 为 1:
PUT my_join_index/_doc/2?routing=1&refresh
{
"text" : "This is an answer",
"my_join_field": {
"name": "answer",
"parent": "1"
}
}
8.数据迁移
索引的映射是不能被修改
新建立 索引
PUT /newbank
{
"mappings": {
"properties": {
"account_number" : {
"type" : "long"
},
"address" : {
"type" : "text"
},
"age" : {
"type" : "integer"
},
"balance" : {
"type" : "long"
},
"city" : {
"type" : "keyword"
},
"email" : {
"type" : "keyword"
},
"employer" : {
"type" : "keyword"
},
"firstname" : {
"type" : "text"
},
"gender" : {
"type" : "keyword"
},
"lastname" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"state" : {
"type" : "keyword"
}
}
}
}
迁移数据
POST _reindex
{
"source": {
"index": "bank",
"type": "account"
},
"dest": {
"index": "newbank"
}
}
返回 表示迁移 1000 条成功
{
"took" : 95,
"timed_out" : false,
"total" : 1000,
"updated" : 0,
"created" : 1000,
"deleted" : 0,
"batches" : 1,
"version_conflicts" : 0,
"noops" : 0,
"retries" : {
"bulk" : 0,
"search" : 0
},
"throttled_millis" : 0,
"requests_per_second" : -1.0,
"throttled_until_millis" : 0,
"failures" : [ ]
}