Elasticsearch:Dynamic field mapping

2022年4月12日   |   by mebius

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

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

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

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

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 mappingAPI 更新现有字段的 dynamic 设置。

你可以自定义 date detectionnumeric detection 的动态字段映射规则。 要定义可应用于其他动态字段的自定义映射规则,请使用 dynamic_templates

我们可以使用如下的例子来进行展示:

PUT test_index
{
  "mappings": {
    "dynamic": "true",
    "date_detection": false, 
    "numeric_detection": false, 
    "properties": {
      "name": {
        "properties": {
          "firstname": {
            "type": "text"
          },
          "lastname": {
            "type": "text"
          }
        }
      }
    }
  }
}

PUT test_index/_doc/1
{
  "null": null,
  "bool": true,
  "double": 1.0,
  "long": 10,
  "name": {
    "firstname": "xiaoguo",
    "lastname": "liu"
  },
  "subjects": ["Math", "Chinese", "English"],
  "date": "2015/09/02",
  "numeric": "1.0"
}


GET test_index/_mapping

在上面,我们创建了一个叫做 test_index 的索引。我们把它的 dynamic 属性设置为 true。那么上面最后的一个命令返回的 mapping 值为:

{
  "test_index" : {
    "mappings" : {
      "dynamic" : "true",
      "date_detection" : false,
      "numeric_detection" : false,
      "properties" : {
        "bool" : {
          "type" : "boolean"
        },
        "date" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "double" : {
          "type" : "float"
        },
        "long" : {
          "type" : "long"
        },
        "name" : {
          "properties" : {
            "firstname" : {
              "type" : "text"
            },
            "lastname" : {
              "type" : "text"
            }
          }
        },
        "numeric" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "subjects" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

我们可以把 dynamic 设置为 runtime。运行如下的命令:

DELETE test_index

PUT test_index
{
  "mappings": {
    "dynamic": "runtime",
    "date_detection": false, 
    "numeric_detection": false, 
    "properties": {
      "name": {
        "properties": {
          "ftgcodeirstname": {
            "type": "text"
          },
          "lastname": {
            "type": "text"
          }
        }
      }
    }
  }
}

PUT test_index/_doc/1
{
  "null": null,
  "bool": true,
  "double": 1.0,
  "long": 10,
  "name": {
    "firstname": "xiaoguo",
    "lastname": "liu"
  },
  "subjects": ["Math", "Chinese", "English"],
  "date": "2015/09/02",
  "numeric": "1.0"
}


GET test_index/_mapping

那么 test_index 的 mapping 为:

{
  "test_index" : {
    "mappings" : {
      "dynamic" : "runtime",
      "date_detection" : false,
      "numeric_detection" : false,
      "runtime" : {
        "bool" : {
          "type" : "boolean"
        },
        "date" : {
          "type" : "keyword"
        },
        "double" : {
          "type" : "double"
        },
        "long" : {
          "type" : "long"
        },
        "numeric" : {
          "type" : "keyword"
        },
        "subjects" : {
          "type" : "keyword"
        }
      },
      "properties" : {
        "name" : {
          "properties" : {
            "firstname" : {
              "type" : "text"
            },
            "lastname" : {
              "type" : "text"
            }
          }
        }
      }
    }
  }

我们和上面的结果比较一下,还是可以找到它们直接的区别的。

Date detection

如果启用 date_detection(默认),则检查新字符串字段以查看其内容是否与 dynamic_date_formats 中指定的任何日期模式匹配。 如果找到匹配项,则会添加一个具有相应格式的新日期字段。

dynamic_date_formats 的默认值为:

[“strict_date_optional_time”,"yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]

例如:

PUT my-index-000001/_doc/1
{
  "create_date": "2015/09/02"
}

上面的命令生成一个叫做my-index-000001 的索引。它的 mapping 是:

GET my-index-000001/_mapping
{
  "my-index-000001" : {
    "mappings" : {
      "properties" : {
        "create_date" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        }
      }
    }
  }
}

在默认的情况下,date detection 是启动的,所以我们可以看到 create_date 被识别为 date 类型的数据。

禁止 date detection

在有些时候,我们可以禁止 date detection,这样摄入的数据可以当做是字符串。可以通过将 date_detection 设置为 false 来禁用动态日期检测:

DELETE my-index-000001

PUT my-index-000001
{
  "mappings": {
    "date_detection": false
  }
}

PUT my-index-000001/_doc/1 
{
  "create_date": "2015/09/02"
}

GET my-index-000001/_mapping

在上面,我们禁止了 date detection。上面最后一个命令返回的 mapping 值如下:

{
  "my-index-000001" : {
    "mappings" : {
      "date_detection" : false,
      "properties" : {
        "create_date" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

显然在这种情况下, create_date 就被当做是一般的 text 来进行处理。

定制 date detection 的日期格式

在上面,我们显示了在默认的情况下日期的检测格式如下:

[“strict_date_optional_time”,"yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]

在实际的很多生产环境中,可能这种格式并不是我们想要的,比如对于中国的许多应用软件,它们的输出格式会和其它地区的格式有所不同。例如:

DELETE my-index-000001

PUT my-index-000001
{
  "mappings": {
    "dynamic_date_formats": ["yyyy年MM月dd日"]
  }
}

PUT my-index-0tgcode00001/_doc/1
{
  "create_date": "2022年03月18日"
}

GET my-index-000001/_mapping

在上面,我们重新定义了 date detection 的日期格式,那么上面最好一个命令的返回的值为:

{
  "my-index-000001" : {
    "mappings" : {
      "dynamic_date_formats" : [
        "yyyy年MM月dd日"
      ],
      "properties" : {
        "create_date" : {
          "type" : "date",
          "format" : "yyyy年MM月dd日"
        }
      }
    }
  }
}

从上面,我们可以看出来 create_date 是一个 date 类型的字段。

Numeric detection

虽然 JSON 支持本机浮点和整数数据类型,但某些应用程序或语言有时可能会将数字呈现为字符串。 通常正确的解决方案是显式映射这些字段,但可以启用 numeric detection(默认情况下禁用)以自动执行此操作:

DELETE my-index-000001

PUT my-index-000001
{
  "mappings": {
    "numeric_detection": true
  }
}

PUT my-tgcodeindex-000001/_doc/1
{
  "my_float":   "1.0", 
  "my_integer": "1" 
}

GET my-index-000001/_mapping

在上面,我们启动了 number detection,那么最后一个命令返回的结果为:

{
  "my-index-000001" : {
    "mappings" : {
      "numeric_detection" : true,
      "properties" : {
        "my_float" : {
          "type" : "float"
        },
        "my_integer" : {
          "type" : "long"
        }
      }
    }
  }
}

更多阅读,请参阅文章 “Elasticsearch:Elasticsearch 中的数据强制匹配”。

文章来源于互联网:Elasticsearch:Dynamic field mapping

Tags: ,