Elasticsearch动态映射与日期类型

Elasticsearch动态映射与日期类型

JSon没有日期类型,但Elasticsearch能自动为我们映射日期字段。如果结合日期字段命名约定可以帮我我们准确实现动态映射。

1. 动态映射

Elasticsearch的动态映射特性可以实现根据字段值自动映射字段类型(缺省类型),因此无需显示定义如何索引、存储字段,Elasticsearch通过检查JSon属性的内容自动推断类型。请看示例:

如果之前没有索引myindex,Elasticsearch会帮助我们做下列工作:

POST /myindex/_doc
{
    "content": "Hello World!",
    "postDate": "2009-11-15T14:12:12"
}
  1. 创建索引myindex,包括两个字段content和postDate
  2. 使用json对象内容增加一个文档

我们来看看Elasticsearch为我们自动创建索引的映射:

GET myindex/_mapping

结果如下:

{
  "myindex" : {
    "mappings" : {
      "properties" : {
        "content" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "postDate" : {
          "type" : "date"
        }
      }
    }
  }
}

content类型默认为text,同时生成content.keyword为keyword类型,同时可以实现全文检索和精确检索。postDate为Date类型。

如果我们通过DELETE /myindex删除上面myindex,而用下面的内容添加索引:

POST /myindex/_doc
{
    "content": "1985-12-24",
    "postDate": "2009-11-15T14:12:12"
}

再次查看映射:

{
  "myindex" : {
    "mappings" : {
      "properties" : {
        "content" : {
          "type" : "date"
        },
        "postDate" : {
          "type" : "date"
        }
      }
    }
  }
}

elasticsearch把content字段也推断了日期类型。如果现在插入原来的文档会报异常:

POST /myindex/_doc
{
    "content": "Hello World!",
    "postDate": "2009-11-15T14:12:12"
}
"caused_by": {
      "type": "illegal_argument_exception",
      "reason": "failed to parse date field [Hello World!] with format [strict_date_optional_time||epoch_millis]"
}
...

我们试图将字符串值插入到映射为日期的字段中,ElasticSearch自然不允许。
虽然这种情况不太可能发生,但发生时会非常恼人,只能通过将所有内容重新索引到新索引中来解决。但幸运的是有许多可能的解决方案。

2. 禁止日期推断

首先我们可以禁用动态映射时日期推断。下面示例显示禁止日期推断:

PUT /myindex
{
  "mappings": {
    "date_detection": false
  }
}

然后在插入文档:

POST /myindex/_doc
{
    "content": "1985-12-24",
    "postDate": "2009-11-15T14:12:12"
}

再查看映射结果为:

{
  "myindex" : {
    "mappings" : {
      "date_detection" : false,
      "properties" : {
        "content" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "postDate" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

现在两个字段内容都包括日期,但都被映射为text类型,并且有子类型keyword。但postDate也被映射为字符串,失去了日期类型的能力。

我们现在显示指定映射日期类型;

PUT /myindex
{
  "mappings": {
    "date_detection": false,
    "properties": {
      "postDate": {
        "type": "date"
      }
    }
  }
}

如果我们再次插入上面问题json内容,映射类型与我们期望的一致。但这种方法不灵活,尤其当有很多字段且有些字段之前并不能确定其类型时。

3. 使用命名规范映射日期字段

另外一种方法禁用日期推断同时显示映射特定字段作为日期类型:

PUT /myindex
{
  "mappings": {
    "date_detection": false,
    "dynamic_templates": [
      {
        "dates": {
          "match": ".*Date|date",
          "match_pattern": "regex",
          "mapping": {
            "type": "date"
          }
        }
      }
    ]
  }
}

比较两者方法有差异。和前面一样也禁用日期推断,但之后不再提供属性映射,而是提供提供基于名称dates动态映射。在名称动态映射中指定正则表达式,符合表达式规范则使用日期类型。

使用这种方法,所有字符串不再会被映射为日期类型,除了其名称以Date结尾,如postDate,updateDate等。

这样虽好,但不能把以Date结尾字段的值设置非日期字符串。但不能否认这种方法还是相对比较灵活,在实际应用中比较可行,毕竟对字段明确一些命名规范也属于数据库设计的一部分。

4. 总结

本文介绍了Elasticsearch的动态映射,并通过如何准确推断日期类型示例进行说明,其他类型也可以使用类似方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章