当 Elasticsearch 在文档中检测到新字段时,默认情况下会动态将该字段添加到类型映射中。 dynamic 参数控制此行为。
你可以通过将 dynamic 参数设置为 true 或 runtime 来明确指示 Elasticsearch 基于传入文档动态创建字段。 启用动态字段映射后,Elasticsearch 使用下表中的规则来确定如何映射每个字段的数据类型。
这篇文章是我之前文章 “Elasticsearch:Dynamic mapping” 的一个补充。
注意:下表中的字段数据类型是 Elasticsearch 动态检测的唯一字段数据类型。 你必须显式映射所有其他数据类型。
| JSON data type | "dynamic": "true" | "dynamic": "runtime" |
|---|---|---|
| null | 不添加任何字段 | 不添加任何字段 |
| true 或者 false | boolean | boolean |
| double | float | double |
| long | long | long |
| object | object | 不添加任何字段 |
| array | 依赖于数组里的第一个非 null 值 | 依赖于数组里的第一个非 null 值 |
| 通过 date detection 的字符串 | date | date |
| 通过 numeric detection 的字符串 | float 或者 long | double 或者 long |
| 不通过 date detection 或者 numberic detection 的字符串 | 含有 .keyword 子字段的 text 类型 | keyword |
你可以在文档和 object 级别禁用动态映射。 将 dynamic 参数设置为 false 会忽略新字段,如果 Elasticsearch 遇到未知字段,把 dynamic 设置为 strict 则会拒绝文档。
提示:使用 update mapping API 更新现有字段的 dynamic 设置。
你可以自定义 date detection 和 numeric detection 的动态字段映射规则。 要定义可应用于其他动态字段的自定义映射规则,请使用 dynamic_templates。
我们可以使用如下的例子来进行展示:
1. PUT test_index
2. {
3. "mappings": {
4. "dynamic": "true",
5. "date_detection": false,
6. "numeric_detection": false,
7. "properties": {
8. "name": {
9. "properties": {
10. "firstname": {
11. "type": "text"
12. },
13. "lastname": {
14. "type": "text"
15. }
16. }
17. }
18. }
19. }
20. }
22. PUT test_index/_doc/1
23. {
24. "null": null,
25. "bool": true,
26. "double": 1.0,
27. "long": 10,
28. "name": {
29. "firstname": "xiaoguo",
30. "lastname": "liu"
31. },
32. "subjects": ["Math", "Chinese", "English"],
33. "date": "2015/09/02",
34. "numeric": "1.0"
35. }
38. GET test_index/_mapping
在上面,我们创建了一个叫做 test_index 的索引。我们把它的 dynamic 属性设置为 true。那么上面最后的一个命令返回的 mapping 值为:
1. {
2. "test_index" : {
3. "mappings" : {
4. "dynamic" : "true",
5. "date_detection" : false,
6. "numeric_detection" : false,
7. "properties" : {
8. "bool" : {
9. "type" : "boolean"
10. },
11. "date" : {
12. "type" : "text",
13. "fields" : {
14. "keyword" : {
15. "type" : "keyword",
16. "ignore_above" : 256
17. }
18. }
19. },
20. "double" : {
21. "type" : "float"
22. },
23. "long" : {
24. "type" : "long"
25. },
26. "name" : {
27. "properties" : {
28. "firstname" : {
29. "type" : "text"
30. },
31. "lastname" : {
32. "type" : "text"
33. }
34. }
35. },
36. "numeric" : {
37. "type" : "text",
38. "fields" : {
39. "keyword" : {
40. "type" : "keyword",
41. "ignore_above" : 256
42. }
43. }
44. },
45. "subjects" : {
46. "type" : "text",
47. "fields" : {
48. "keyword" : {
49. "type" : "keyword",
50. "ignore_above" : 256
51. }
52. }
53. }
54. }
55. }
56. }
57. }
我们可以把 dynamic 设置为 runtime。运行如下的命令:
1. DELETE test_index
3. PUT test_index
4. {
5. "mappings": {
6. "dynamic": "runtime",
7. "date_detection": false,
8. "numeric_detection": false,
9. "properties": {
10. "name": {
11. "properties": {
12. "firstname": {
13. "type": "text"
14. },
15. "lastname": {
16. "type": "text"
17. }
18. }
19. }
20. }
21. }
22. }
24. PUT test_index/_doc/1
25. {
26. "null": null,
27. "bool": true,
28. "double": 1.0,
29. "long": 10,
30. "name": {
31. "firstname": "xiaoguo",
32. "lastname": "liu"
33. },
34. "subjects": ["Math", "Chinese", "English"],
35. "date": "2015/09/02",
36. "numeric": "1.0"
37. }
40. GET test_index/_mapping
那么 test_index 的 mapping 为:
1. {
2. "test_index" : {
3. "mappings" : {
4. "dynamic" : "runtime",
5. "date_detection" : false,
6. "numeric_detection" : false,
7. "runtime" : {
8. "bool" : {
9. "type" : "boolean"
10. },
11. "date" : {
12. "type" : "keyword"
13. },
14. "double" : {
15. "type" : "double"
16. },
17. "long" : {
18. "type" : "long"
19. },
20. "numeric" : {
21. "type" : "keyword"
22. },
23. "subjects" : {
24. "type" : "keyword"
25. }
26. },
27. "properties" : {
28. "name" : {
29. "properties" : {
30. "firstname" : {
31. "type" : "text"
32. },
33. "lastname" : {
34. "type" : "text"
35. }
36. }
37. }
38. }
39. }
40. }
我们和上面的结果比较一下,还是可以找到它们直接的区别的。
Date detection
如果启用 date_detection(默认),则检查新字符串字段以查看其内容是否与 dynamic_date_formats 中指定的任何日期模式匹配。 如果找到匹配项,则会添加一个具有相应格式的新日期字段。
dynamic_date_formats 的默认值为:
[ ["strict_date_optional_time"](www.elastic.co/guide/en/el… ""strict_date_optional_time""),"yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
例如:
1. PUT my-index-000001/_doc/1
2. {
3. "create_date": "2015/09/02"
4. }
上面的命令生成一个叫做 my-index-000001 的索引。它的 mapping 是:
GET my-index-000001/_mapping
1. {
2. "my-index-000001" : {
3. "mappings" : {
4. "properties" : {
5. "create_date" : {
6. "type" : "date",
7. "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
8. }
9. }
10. }
11. }
12. }
在默认的情况下,date detection 是启动的,所以我们可以看到 create_date 被识别为 date 类型的数据。
禁止 date detection
在有些时候,我们可以禁止 date detection,这样摄入的数据可以当做是字符串。可以通过将 date_detection 设置为 false 来禁用动态日期检测:
1. DELETE my-index-000001
3. PUT my-index-000001
4. {
5. "mappings": {
6. "date_detection": false
7. }
8. }
10. PUT my-index-000001/_doc/1
11. {
12. "create_date": "2015/09/02"
13. }
15. GET my-index-000001/_mapping
在上面,我们禁止了 date detection。上面最后一个命令返回的 mapping 值如下:
1. {
2. "my-index-000001" : {
3. "mappings" : {
4. "date_detection" : false,
5. "properties" : {
6. "create_date" : {
7. "type" : "text",
8. "fields" : {
9. "keyword" : {
10. "type" : "keyword",
11. "ignore_above" : 256
12. }
13. }
14. }
15. }
16. }
17. }
18. }
显然在这种情况下, create_date 就被当做是一般的 text 来进行处理。
定制 date detection 的日期格式
在上面,我们显示了在默认的情况下日期的检测格式如下:
[ ["strict_date_optional_time"](www.elastic.co/guide/en/el… ""strict_date_optional_time""),"yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
在实际的很多生产环境中,可能这种格式并不是我们想要的,比如对于中国的许多应用软件,它们的输出格式会和其它地区的格式有所不同。例如:
1. DELETE my-index-000001
3. PUT my-index-000001
4. {
5. "mappings": {
6. "dynamic_date_formats": ["yyyy年MM月dd日"]
7. }
8. }
10. PUT my-index-000001/_doc/1
11. {
12. "create_date": "2022年03月18日"
13. }
15. GET my-index-000001/_mapping
在上面,我们重新定义了 date detection 的日期格式,那么上面最好一个命令的返回的值为:
1. {
2. "my-index-000001" : {
3. "mappings" : {
4. "dynamic_date_formats" : [
5. "yyyy年MM月dd日"
6. ],
7. "properties" : {
8. "create_date" : {
9. "type" : "date",
10. "format" : "yyyy年MM月dd日"
11. }
12. }
13. }
14. }
15. }
从上面,我们可以看出来 create_date 是一个 date 类型的字段。
Numeric detection
虽然 JSON 支持本机浮点和整数数据类型,但某些应用程序或语言有时可能会将数字呈现为字符串。 通常正确的解决方案是显式映射这些字段,但可以启用 numeric detection(默认情况下禁用)以自动执行此操作:
1. DELETE my-index-000001
3. PUT my-index-000001
4. {
5. "mappings": {
6. "numeric_detection": true
7. }
8. }
10. PUT my-index-000001/_doc/1
11. {
12. "my_float": "1.0",
13. "my_integer": "1"
14. }
16. GET my-index-000001/_mapping
在上面,我们启动了 number detection,那么最后一个命令返回的结果为:
1. {
2. "my-index-000001" : {
3. "mappings" : {
4. "numeric_detection" : true,
5. "properties" : {
6. "my_float" : {
7. "type" : "float"
8. },
9. "my_integer" : {
10. "type" : "long"
11. }
12. }
13. }
14. }
15. }
更多阅读,请参阅文章 “Elasticsearch:Elasticsearch 中的数据强制匹配”。