Elasticsearch:Dynamic field mapping

532 阅读6分钟

当 Elasticsearch 在文档中检测到新字段时,默认情况下会动态将该字段添加到类型映射中。 dynamic 参数控制此行为。

你可以通过将 dynamic 参数设置为 true 或 runtime 来明确指示 Elasticsearch 基于传入文档动态创建字段。 启用动态字段映射后,Elasticsearch 使用下表中的规则来确定如何映射每个字段的数据类型。

这篇文章是我之前文章 “Elasticsearch:Dynamic mapping” 的一个补充。

注意:下表中的字段数据类型是 Elasticsearch 动态检测的唯一字段数据类型。 你必须显式映射所有其他数据类型。

Elasticsearch 数据类型
JSON data type "dynamic": "true""dynamic": "runtime"
null不添加任何字段不添加任何字段
true 或者 falsebooleanboolean
doublefloatdouble
longlonglong
objectobject不添加任何字段
array依赖于数组里的第一个非 null 值依赖于数组里的第一个非 null 值
通过 date detection 的字符串datedate
通过 numeric detection 的字符串float 或者 longdouble 或者 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 中的数据强制匹配”。