当前位置:   article > 正文

【Elasticsearch学习笔记二】es的Mapping字段映射、Mapping字段常用类型、Mapping映射的创建、查看和更新、es数据迁移、ik分词器_es mapping

es mapping

目录

1、Mapping字段映射概述

2、Mapping字段常用类型

3、映射中对时间类型详解

1)采取自动映射器来映射

2)手工映射提前指定日期类型

4、ES的keyword的属性ignore_above

5、Mapping映射的查看和创建

1)查看mapping信息:GET 索引名/_mapping

2)创建映射:PUT /索引名

3) 查看所有索引映射关系

4)修改索引映射关系

5)一次性创建索引和映射

6、数据迁移-reindex

7、ik_max_word、ik_smart分词器


1、Mapping字段映射概述

        映射(Mapping)相当于数据表的表结构。ElasticSearch中的映射(Mapping)用来定义一个文档,可以定义所包含的字段以及字段的类型、分词器及属性等等

        映射可以分为动态映射和静态映射:

  1. 动态映射(dynamic mapping):在关系数据库中,需要事先创建数据库,然后在该数据库实例下创建数据表,然后才能在该数据表中插入数据。而ElasticSearch中不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型。这种机制称之为动态映射
  2. 静态映射 :在ElasticSearch中也可以事先定义好映射,包含文档的各个字段及其类型等,这种方式称之为静态映射

2、Mapping字段常用类型

1)字符串(text、keyword)

  • text:可分词,不可参与聚合
  • keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合

 2)整数

 3)浮点类型

 4)date类型

  • 日期格式的字符串,比如"2018-01-13"或"2018-01-13 12:10:30"
  • long类型的毫秒数(从1970年开始)
  • integer的秒数

5) boolean类型

        逻辑类型(布尔类型)可以接受true/false

6) binary类型

        二进制字段是指base64来表示索引中储存的二进制数据,可用来储存二进制形式的数据,例如图像。默认情况下,该类型的字段只储存不索引。二进制只支持index_name属性

7)array类型

8)object类型

        JSON天生具有层级关系,文档会包含嵌套的对象

3、映射中对时间类型详解

        假如我们有如下索引tax,保存了一些公司的纳税或资产信息,单位为"万元"。当前这个例子里。索引达的含义并不重要,关键点在于字段的内容格式。我们看到date字段其中包含了多种日期的格式:“yyyy-MM-dd”,"yyyy-MM-dd"还有时间戳。

1)采取自动映射器来映射

        如果按照dynamic mapping,采取自动映射器来映射索引,我们自然而然的都会感觉字段应该是一个date类型;我们把数据存入索引然后查看tax索引的mapping;

  1. POST tax/_bulk
  2. {"index":{}}
  3. {"date": "2021-01-27 10:01:54","company": "腾讯","ratal": 6500}
  4. {"index":{}}
  5. {"date": "2021-01-28 10:01:32","company": "蚂蚁金服","ratal": 5000}
  6. {"index":{}}
  7. {"date": "2021-01-29 10:01:21","company": "字节跳动","ratal": 10000}
  8. {"index":{}}
  9. {"date": "2021-01-30 10:02:07","company": "中国石油","ratal": 18302097}
  10. {"index":{}}
  11. {"date": "1648100904","company": "中国石化","ratal": 32654722}
  12. {"index":{}}
  13. {"date": "2021-11-1 12:20:00","company": "国家电网","ratal": 82950000}

查看tax索引的mapping:

  1. "properties" : {
  2. "date" : {
  3. "type" : "text","fields" : {
  4. "keyword" : {
  5. "type" : "keyword","ignore_above" : 256
  6. }
  7. }
  8. }
  9. }

        我们可以看到date居然是一个text类型。这是为什么呢,原因就在于对时间类型的格式的要求是绝对严格的。要求必须是一个标准的UTC时间类型。上述字段的数据格式如果想要使用,就必须使用yyyy-MM-ddTHH:mm:ssZ格式(其中T个间隔符,Z代表 0 时区);

        错误的时间格式均无法被自动映射器识别为日期时间类型,例如:

  1. yyyy-MM-dd HH:mm:ss
  2. yyyy-MM-dd
  3. 时间戳
  4. 2022-4-30T20:00:00Z

2)手工映射提前指定日期类型

  1. PUT tax
  2. {
  3. "mappings": {
  4. "properties": {
  5. "date": {
  6. "type": "date"
  7. }
  8. }
  9. }
  10. }
  11. POST tax/_bulk
  12. {"index":{}}
  13. {"date": "2021-01-30 10:02:07","ratal": 32654722}
  14. {"index":{}}
  15. {"date": "2021-11-1T12:20:00Z","ratal": 82950000}
  16. {"index":{}}
  17. {"date": "2021-01-30T10:02:07Z","ratal": 18302097}
  18. {"index":{}}
  19. {"date": "2021-01-25","ratal": 5700000}

第一个(写入失败):2021-01-30 10:02:07

第二个(写入成功):1648100904

第三个(写入失败):2021-11-1T12:20:00Z

第四个(写入成功):2021-01-30T10:02:07Z

第五个(写入成功):2021-01-25

总结:

1.对于yyyy-MM-dd HH:mm:ss或2021-11-1T12:20:00Z,ES 的自动映射器完全无法识别,即便是事先声明日期类型,数据强行写入也会失败

2.对于时间戳和yyyy-MM-dd这样的时间格式,ES 自动映射器无法识别,但是如果事先说明了日期类型是可以正常写入的

3.对于标准的日期时间类型是可以正常自动识别为日期类型,并且也可以通过手工映射来实现声明字段类型

实际开发中的解决方法:

  1. //只需要在字段属性中添加一个参数:
  2. format”: “yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis”,这样就可以避免因为数据格式不统一而导致数据无法写入的窘境
  3. PUT test_index
  4. {
  5. "mappings": {
  6. "properties": {
  7. "time": {
  8. "type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
  9. }
  10. }
  11. }
  12. }

4、ES的keyword的属性ignore_above

        在es的5.x版本,keyword类型字段可以设置ignore_above,表示最大的字段值长度,超出这个长度的字段将不会被索引,但是会存储;举个例子:设置message 的长度最长为20,超过20的不被索引,这里的不被索引是这个字段不被索引,但是其他字段有的话仍然被索引到;

  1. PUT my_index
  2. {
  3. "mappings": {
  4. "my_type": {
  5. "properties": {
  6. "message": {
  7. "type": "keyword",
  8. "ignore_above": 20
  9. }
  10. }
  11. }
  12. }
  13. }
  14. # 下面造点数据
  15. PUT my_index/my_type/3
  16. {
  17. "message": "123456789"
  18. }
  19. PUT my_index/my_type/5
  20. {
  21. "message": "123456789012345678901"
  22. }

全部查询:

 模糊匹配:

在这里插入图片描述

        我们可以发现你用模糊匹配是搜索不到的(注意上面的数据最后带个1是21位下图是20位的),同样 用精确匹配前面20个仍然搜索不到;

5、Mapping映射的查看和创建

1)查看mapping信息:GET 索引名/_mapping

  1. {
  2. "bank" : {
  3. "mappings" : {
  4. "properties" : {
  5. "account_number" : {
  6. "type" : "long" # long类型
  7. },
  8. "address" : {
  9. "type" : "text", # 文本类型,会进行全文检索,进行分词
  10. "fields" : {
  11. "keyword" : { # addrss.keyword
  12. "type" : "keyword", # 该字段必须全部匹配到
  13. "ignore_above" : 256
  14. }
  15. }
  16. },
  17. "age" : {
  18. "type" : "long"
  19. },
  20. "balance" : {
  21. "type" : "long"
  22. },
  23. "city" : {
  24. "type" : "text",
  25. "fields" : {
  26. "keyword" : {
  27. "type" : "keyword",
  28. "ignore_above" : 256
  29. }
  30. }
  31. },
  32. "email" : {
  33. "type" : "text",
  34. "fields" : {
  35. "keyword" : {
  36. "type" : "keyword",
  37. "ignore_above" : 256
  38. }
  39. }
  40. },
  41. "employer" : {
  42. "type" : "text",
  43. "fields" : {
  44. "keyword" : {
  45. "type" : "keyword",
  46. "ignore_above" : 256
  47. }
  48. }
  49. },
  50. "firstname" : {
  51. "type" : "text",
  52. "fields" : {
  53. "keyword" : {
  54. "type" : "keyword",
  55. "ignore_above" : 256
  56. }
  57. }
  58. },
  59. "gender" : {
  60. "type" : "text",
  61. "fields" : {
  62. "keyword" : {
  63. "type" : "keyword",
  64. "ignore_above" : 256
  65. }
  66. }
  67. },
  68. "lastname" : {
  69. "type" : "text",
  70. "fields" : {
  71. "keyword" : {
  72. "type" : "keyword",
  73. "ignore_above" : 256
  74. }
  75. }
  76. },
  77. "state" : {
  78. "type" : "text",
  79. "fields" : {
  80. "keyword" : {
  81. "type" : "keyword",
  82. "ignore_above" : 256
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. }

ElasticSearch7-去掉type概念:

1、关系型数据库中两个数据表示是独立的,即使他们里面有相同名称的列也不影响使用,但ES中不是这样的。elasticsearch是基于Lucene开发的搜索引擎,而ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的

  • (1)两个不同type下的两个user_name,在ES同一个索引下其实被认为是同一个filed,你必须在两个不同的type中定义相同的filed映射。否则,不同type中的相同字段名称就会在处理中出现冲突的情况,导致Lucene处理效率下降。
  • (2)去掉type就是为了提高ES处理数据的效率。

2、Elasticsearch 7.x URL中的type参数为可选。比如,索引一个文档不再要求提供文档类型
3、Elasticsearch 8.x 不再支持URL中的type参数

解决:将索引从多类型迁移到单类型,每种类型文档一个独立索引;将已存在的索引下的类型数据,全部迁移到指定位置即可;

2)创建映射:PUT /索引名

创建Mapping映射语法:

  1. PUT /索引库名/_mapping
  2. {
  3. "properties": {
  4. "字段名": {
  5. "type": "类型", # type:类型,可以是text、long、short、date、integer、object
  6. "index": true, # index:是否索引,默认为true
  7. "store": false, # store:是否存储,默认为false
  8. "analyzer": "分词器" # analyzer:指定分词器
  9. }
  10. }
  11. }
  12. PUT /company-index/_mapping
  13. {
  14. "properties": {
  15. "name": {
  16. "type": "text",
  17. "index": true,
  18. "analyzer": "ik_max_word"
  19. },
  20. "job": {
  21. "type": "text",
  22. "analyzer": "ik_max_word"
  23. },
  24. "logo": {
  25. "type": "keyword",
  26. "index": false
  27. },
  28. "payment": {
  29. "type": "float"
  30. }
  31. }
  32. }

1、index影响字段的索引情况:

  • true:字段会被索引,则可以用来进行搜索。默认值就是true
  • false:字段不会被索引,不能用来搜索

        index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。但是有些字段是我们不希望被索引的,比如企业的logo图片地址,就需要手动设置index为false;

2、store:是否将数据进行独立存储:

        原始的文本会存储在_source里面,默认情况下其他提取出来的字段都不是独立存储的,是从_source里面提取出来的。当然你也可以独立的存储某个字段,只要设置store:true即可,获取独立存储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置,默认为false;

3、analyzer:指定分词器:

        一般我们处理中文会选择ik分词器 ik_max_word、ik_smart

  1. PUT /my_index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "age": {
  6. "type": "integer"
  7. },
  8. "email": {
  9. "type": "keyword" # 指定为keyword
  10. },
  11. "name": {
  12. "type": "text" # 全文检索。保存时候分词,检索时候进行分词匹配
  13. }
  14. }
  15. }
  16. }
  17. 输出:
  18. {
  19. "acknowledged" : true,
  20. "shards_acknowledged" : true,
  21. "index" : "my_index"
  22. }
  23. 查看映射GET /my_index
  24. 输出结果:
  25. {
  26. "my_index" : {
  27. "aliases" : { },
  28. "mappings" : {
  29. "properties" : {
  30. "age" : {
  31. "type" : "integer"
  32. },
  33. "email" : {
  34. "type" : "keyword"
  35. },
  36. "employee-id" : {
  37. "type" : "keyword",
  38. "index" : false
  39. },
  40. "name" : {
  41. "type" : "text"
  42. }
  43. }
  44. },
  45. "settings" : {
  46. "index" : {
  47. "creation_date" : "1588410780774",
  48. "number_of_shards" : "1",
  49. "number_of_replicas" : "1",
  50. "uuid" : "ua0lXhtkQCOmn7Kh3iUu0w",
  51. "version" : {
  52. "created" : "7060299"
  53. },
  54. "provided_name" : "my_index"
  55. }
  56. }
  57. }
  58. }
  59. # 添加新的字段映射PUT /my_index/_mapping
  60. PUT /my_index/_mapping
  61. {
  62. "properties": {
  63. "employee-id": {
  64. "type": "keyword",
  65. "index": false # 字段不能被检索。检索
  66. }
  67. }
  68. }
  69. 这里的 "index": false,表明新增的字段不能被检索,只是一个冗余字段。

注意:不能更新映射:对于已经存在的字段映射,我们不能更新。更新必须创建新的索引,进行数据迁移

3) 查看所有索引映射关系

  1. GET _mapping
  2. GET _all/_mapping

4)修改索引映射关系

  1. PUT /索引库名/_mapping
  2. {
  3. "properties": {
  4. "字段名": {
  5. "type": "类型",
  6. "index": true,
  7. "store": true,
  8. "analyzer": "分词器"
  9. }
  10. }
  11. }

注意:这里修改映射是增加字段,做其它更改只能删除索引重新建立映射

5)一次性创建索引和映射

  1. put /索引库名称
  2. {
  3. "settings": {
  4. "索引库属性名": "索引库属性值"
  5. },
  6. "mappings": {
  7. "properties": {
  8. "字段名": {
  9. "映射属性名": "映射属性值"
  10. }
  11. }
  12. }
  13. }

6、数据迁移-reindex

        先创建new_twitter的正确映射,然后使用如下方式进行数据迁移

  1. 6.0以后写法
  2. POST reindex
  3. {
  4. "source":{
  5. "index":"twitter"
  6. },
  7. "dest":{
  8. "index":"new_twitters"
  9. }
  10. }
  11. 老版本写法
  12. POST reindex
  13. {
  14. "source":{
  15. "index":"twitter",
  16. "type":"twitter"
  17. },
  18. "dest":{
  19. "index":"new_twitters"
  20. }
  21. }

案例:原来类型为account,新版本没有类型了,所以我们把他去掉;想要将年龄修改为integer,先创建新的索引;

1.原索引:

  1. GET /bank/_search
  2. {
  3. "took" : 0,
  4. "timed_out" : false,
  5. "_shards" : {
  6. "total" : 1,
  7. "successful" : 1,
  8. "skipped" : 0,
  9. "failed" : 0
  10. },
  11. "hits" : {
  12. "total" : {
  13. "value" : 1000,
  14. "relation" : "eq"
  15. },
  16. "max_score" : 1.0,
  17. "hits" : [
  18. {
  19. "_index" : "bank",
  20. "_type" : "account",//原来类型为account,新版本没有类型了,所以我们把他去掉
  21. "_id" : "1",
  22. "_score" : 1.0,
  23. "_source" : {
  24. "account_number" : 1,
  25. "balance" : 39225,
  26. "firstname" : "Amber",
  27. "lastname" : "Duke",
  28. "age" : 32,
  29. "gender" : "M",
  30. "address" : "880 Holmes Lane",
  31. "employer" : "Pyrami",
  32. "email" : "amberduke@pyrami.com",
  33. "city" : "Brogan",
  34. "state" : "IL"
  35. }
  36. },
  37. ...
  38. GET /bank/_search
  39. 查出
  40. "age":{"type":"long"}

2.创建新的索引:

  1. PUT /newbank
  2. {
  3. "mappings": {
  4. "properties": {
  5. "account_number": {
  6. "type": "long"
  7. },
  8. "address": {
  9. "type": "text"
  10. },
  11. "age": {
  12. "type": "integer"
  13. },
  14. "balance": {
  15. "type": "long"
  16. },
  17. "city": {
  18. "type": "keyword"
  19. },
  20. "email": {
  21. "type": "keyword"
  22. },
  23. "employer": {
  24. "type": "keyword"
  25. },
  26. "firstname": {
  27. "type": "text"
  28. },
  29. "gender": {
  30. "type": "keyword"
  31. },
  32. "lastname": {
  33. "type": "text",
  34. "fields": {
  35. "keyword": {
  36. "type": "keyword",
  37. "ignore_above": 256
  38. }
  39. }
  40. },
  41. "state": {
  42. "type": "keyword"
  43. }
  44. }
  45. }
  46. }
  47. 查看"newbank"的映射:
  48. GET /newbank/_mapping
  49. 能够看到age的映射类型被修改为了integer.
  50. "age":{"type":"integer"}

3.将bank中的数据迁移到newbank中:

  1. POST _reindex
  2. {
  3. "source": {
  4. "index": "bank",
  5. "type": "account"
  6. },
  7. "dest": {
  8. "index": "newbank"
  9. }
  10. }
  11. 运行输出:
  12. #! Deprecation: [types removal] Specifying types in reindex requests is deprecated.
  13. {
  14. "took" : 768,
  15. "timed_out" : false,
  16. "total" : 1000,
  17. "updated" : 0,
  18. "created" : 1000,
  19. "deleted" : 0,
  20. "batches" : 1,
  21. "version_conflicts" : 0,
  22. "noops" : 0,
  23. "retries" : {
  24. "bulk" : 0,
  25. "search" : 0
  26. },
  27. "throttled_millis" : 0,
  28. "requests_per_second" : -1.0,
  29. "throttled_until_millis" : 0,
  30. "failures" : [ ]
  31. }

4.查看newbank中的数据:

  1. GET /newbank/_search
  2. 输出
  3. "hits" : {
  4. "total" : {
  5. "value" : 1000,
  6. "relation" : "eq"
  7. },
  8. "max_score" : 1.0,
  9. "hits" : [
  10. {
  11. "_index" : "newbank",
  12. "_type" : "_doc", # 没有了类型

7、ik_max_word、ik_smart分词器

        一个tokenizer(分词器)接收一个字符流,将之分割为独立的tokens(词元,通常是独立的单词),然后输出tokens流;例如:whitespace tokenizer遇到空白字符时分割文本。它会将文本"Quick brown fox!"分割为(Quick,brown,fox!);

        该tokenizer(分词器)还负责记录各个terms(词条)的顺序或position位置(用于phrase短语和word proximity词近邻查询),以及term(词条)所代表的原始word(单词)的start(起始)和end(结束)的character offsets(字符串偏移量)(用于高亮显示搜索的内容)。elasticsearch提供了很多内置的分词器(标准分词器),可以用来构建custom analyzers(自定义分词器)。

        分词器的安装:根据当前es的版本,去找到对应版本的分词器,下载.zip文件,然后解压到elasticsearch/plugins文件夹下即可,注意需要将权限进行修改chmod -R 777 plugins/ik;安装完毕后,需要重启elasticsearch容器。

  1. POST _analyze
  2. {
  3. "analyzer": "standard",
  4. "text": "The 2 Brown-Foxes bone."
  5. }
  6. 执行结果:
  7. {
  8. "tokens" : [
  9. {
  10. "token" : "the",
  11. "start_offset" : 0,
  12. "end_offset" : 3,
  13. "type" : "<ALPHANUM>",
  14. "position" : 0
  15. },
  16. {
  17. "token" : "2",
  18. "start_offset" : 4,
  19. "end_offset" : 5,
  20. "type" : "<NUM>",
  21. "position" : 1
  22. },
  23. {
  24. "token" : "brown",
  25. "start_offset" : 6,
  26. "end_offset" : 11,
  27. "type" : "<ALPHANUM>",
  28. "position" : 2
  29. },
  30. {
  31. "token" : "foxes",
  32. "start_offset" : 12,
  33. "end_offset" : 17,
  34. "type" : "<ALPHANUM>",
  35. "position" : 3
  36. },
  37. {
  38. "token" : "bone",
  39. "start_offset" : 18,
  40. "end_offset" : 22,
  41. "type" : "<ALPHANUM>",
  42. "position" : 4
  43. }
  44. ]
  45. }

        ik_max_word:会将文本做最细粒度的拆分,比如会将"湖南省岳阳县"拆分为"湖南省、湖南、省、 岳阳县、岳阳、县等词语(索引的时候用ik_max_word):

  1. GET _analyze
  2. {
  3. "analyzer": "ik_max_word",
  4. "text":"湖南省岳阳县"
  5. }
  6. {
  7. "tokens" : [
  8. {
  9. "token" : "湖南省",
  10. "start_offset" : 0,
  11. "end_offset" : 3,
  12. "type" : "CN_WORD",
  13. "position" : 0
  14. },
  15. {
  16. "token" : "湖南",
  17. "start_offset" : 0,
  18. "end_offset" : 2,
  19. "type" : "CN_WORD",
  20. "position" : 1
  21. },
  22. {
  23. "token" : "省",
  24. "start_offset" : 2,
  25. "end_offset" : 3,
  26. "type" : "CN_CHAR",
  27. "position" : 2
  28. },
  29. {
  30. "token" : "岳阳县",
  31. "start_offset" : 3,
  32. "end_offset" : 6,
  33. "type" : "CN_WORD",
  34. "position" : 3
  35. },
  36. {
  37. "token" : "岳阳",
  38. "start_offset" : 3,
  39. "end_offset" : 5,
  40. "type" : "CN_WORD",
  41. "position" : 4
  42. },
  43. {
  44. "token" : "县",
  45. "start_offset" : 5,
  46. "end_offset" : 6,
  47. "type" : "CN_CHAR",
  48. "position" : 5
  49. }
  50. ]
  51. }

        ik_smart:会做最粗粒度的拆分,比如会将"湖南省岳阳县"拆分为湖南省、岳阳县(前台搜索的时候用 ik_smart):

  1. GET _analyze
  2. {
  3. "analyzer": "ik_smart",
  4. "text":"湖南省岳阳县"
  5. }
  6. {
  7. "tokens" : [
  8. {
  9. "token" : "湖南省",
  10. "start_offset" : 0,
  11. "end_offset" : 3,
  12. "type" : "CN_WORD",
  13. "position" : 0
  14. },
  15. {
  16. "token" : "岳阳县",
  17. "start_offset" : 3,
  18. "end_offset" : 6,
  19. "type" : "CN_WORD",
  20. "position" : 1
  21. }
  22. ]
  23. }

        用户还可以通过修改elasticsearch/plugins/ik/config中的IKAnalyzer.cfg.xml文件自定义分词器;

参考原文地址:http://t.csdn.cn/WK4mn

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/503728
推荐阅读
相关标签
  

闽ICP备14008679号