document中每一个field的数据类型可以通过types来设置。
1:主类型
每一个json field都可以对应到一个特定的主类型,json本身就提供了很多类型。
string/byte/short/integer/long/float/double/boolean/binary/date/null。
以上数据类型跟通常的数据类型一样,没什么特殊性。下边介绍一些特有的:
token_count:这种类型索引和存储的是json串中的token数目,而非json串本身。因此需要携带一个analyzer。为了达到最佳性能,采用no token filter的analyzer。
注意:token_count不会忽略stop words。
fielddata filters:这不是一种数据类型,只是一个配置项。可以控制field的哪些value可以加载到内存中,在对string field进行facet时尤其有用。fielddata filter可以排除不满足条件的terms,比如无法匹配到指定的正则,tf不在指定范围内等。下边是一个例子:
{ tweet: { type: "string", analyzer: "whitespace" fielddata: { filter: { regex: { "pattern": "^#.*" }, frequency: { min: 0.001, max: 0.1, min_segment_size: 500 } } } } }similarity:es允许给field配置一个相似性算法,默认的TF/IDF。
copy to field:copy_to参数将指定该field中的所有value都将拷贝到参数指定的field中。比如:
{ "book" : { "properties" : { "title" : { "type" : "string", "copy_to" : "meta_data" }, "abstract" : { "type" : "string", "copy_to" : "meta_data" }, "meta_data" : { "type" : "string" } } }同样支持多个field,比如:
{ "book" : { "properties" : { "title" : { "type" : "string", "copy_to" : ["meta_data", "article_info"] } } }multi field:同一个json串指定不同的处理方式。比如:
{ "tweet" : { "properties" : { "name" : { "type" : "string", "index" : "analyzed", "fields" : { "raw" : {"type" : "string", "index" : "not_analyzed"} } } } } }
name字段被处理的两次,一次采用默认的analyzer,另一次完全跳过analysis过程。因此衍生出一种访问方式:name.raw.
field的include_in_all属性决定该field是否应该被包含到_all字段中。在multi_field的情况下,该设置只对主字段有效,在fields中的设置会忽略。
在本质上field是无法更新的。但是muti fields可以添加到已经存在的field中。这就允许在主字段已经存在一个分词器的情况下,再添加另外一个分词器。当然新添加的muti field设置也只是对添加之后再进入索引的文档有效,之前的文档当然是无效的。Another important note is that new multi fields will be merged into the list of existing multi fields, so when adding new multi fields for a field previous added multi fields don’t need to be specified.
2:array type
json可以支持数组,数组内容可以是主类型,当然也可以是对象类型。对array类型不能被简单的mapping,因为array类型是自动检测的,并且要用core type或者object type来映射。如下:
{
"tweet" : {
"message" : "some arrays in this tweet...",
"tags" : ["elasticsearch", "wow"],
"lists" : [
{
"name" : "prog_list",
"description" : "programming list"
},
{
"name" : "cool_list",
"description" : "cool stuff list"
}
]
}
}
以上tags是一个string数组,而lists是一个对象数组。
下边是以上document的一个显式的mapping设置:
{
"tweet" : {
"properties" : {
"message" : {"type" : "string"},
"tags" : {"type" : "string", "index_name" : "tag"},
"lists" : {
"properties" : {
"name" : {"type" : "string"},
"description" : {"type" : "string"}
}
}
}
}
}
注意:tags的index_name属性。
事实上,array类型是可以被自动支持的。以下document也是ok的:
{
"tweet" : {
"message" : "some arrays in this tweet...",
"tags" : "elasticsearch",
"lists" : {
"name" : "prog_list",
"description" : "programming list"
}
}
}
注意:我们可以用index_name来访问array中的单数形式数据(以上例子中用tag来代替tags),事实上我们可以直接用index_name来直接访问。
比如:我们可以用tweet.tags来访问该字段,也可以用用tweet.tag来访问.
其实index_name只是为了array的单数形式设置的,在导入数据的时候如果发现是单数形式,可以直接用index_name这个属性(这时候source字段是不带方括号,当然如果是单数形式也用了tags字段,source也是不带方括号的)。而在查询的时候,既可以用tags,也可以用tag。
3:object type
json是结构化的数据,可以嵌套。es对这种结构化数据进行了合理的映射,而且是动态的。
{ "tweet" : { "person" : { "name" : { "first_name" : "Shay", "last_name" : "Banon" }, "sid" : "12345" }, "message" : "This is a tweet!" } }person就是一个object,同时tweet也是object,尽管是一个特殊的root object type。下边是一个显式的object mapping
{ "tweet" : { "properties" : { "person" : { "type" : "object", "properties" : { "name" : { "type" : "object", "properties" : { "first_name" : {"type" : "string"}, "last_name" : {"type" : "string"} } }, "sid" : {"type" : "string", "index" : "not_analyzed"} } }, "message" : {"type" : "string"} } } }name的type设置为object。其实这要设置了properties属性,会自动定义为object类型。
properties定了了object的各个field,其中的field仍然可以定义为object或者是core-type
es一个重要特性就是动态mapping,以上例子中如果在person的document中出现了新的field,比如age,则会自动添加到mapping中。可以关闭dynamic属性,这样就会拒绝不在mapping中的数据。dynamic没有任何额外的负载,关闭只是为了防止不符合格式的数据进入。dynamic在第一条数据进入的时候会自动推测数据类型,添加到mapping中,比如如果是一个number,则会自动映射到number的core type,其他属性采用默认值。日期类型有些特殊,因为是用string表示,在进入es的时候,parse之后可以认为是一个日期类型,可以配置dynamic_date_formats来设置日期的格式。
注意:一旦一个field的类型被确定了,就无法更改。
enabled标志可以让object的parse和index失效,也就是说在这个对象将不会被索引。当json doc中有部分包含随意的json信息而不应该被索引的时候,设置mapping中的enable属性即可。
{ "tweet" : { "properties" : { "person" : { "type" : "object", "properties" : { "name" : { "type" : "object", "enabled" : false }, "sid" : {"type" : "string", "index" : "not_analyzed"} } }, "message" : {"type" : "string"} } } }以上,name及其内容将不会被索引。
include_in_all可以设置在object type的级别上,会自动延伸到内部的mapping中。
4:root object type
root object mapping是对type本身的映射。对object type适用的mapping对root object 也适用。root object typemapping允许索引不指定type的document。比如:
{
“message” : “This is a tweet”
}
可以指定type级别的过滤器类型:
{
"tweet" : {
"index_analyzer" : "standard",
"search_analyzer" : "standard"
}
}
在任何没有显式指定的field中的过滤器自动应用以上设置。
可以设置动态date类型的格式:
{
"tweet" : {
"dynamic_date_formats" : ["yyyy-MM-dd", "dd-MM-yyyy"],
"properties" : {
"message" : {"type" : "string"}
}
}
}
如果检测到一个string是date,则标记为date类型,采用以上设置的格式。
注意:以上设置只能针对动态date,不适用于在mapping中显式指定的date类型。
可以设置是否允许date的自动检测:
{
"tweet" : {
"date_detection" : false,
"properties" : {
"message" : {"type" : "string"}
}
}
}
可以设置number类型的自动检测(有时候number类型是用string传递过来的):
{
"tweet" : {
"numeric_detection" : true,
"properties" : {
"message" : {"type" : "string"}
}
}
}
可以设置动态模板(注意,只对确实有value的field有效,如果是null,则并不会应用),如下:
{
"person" : {
"dynamic_templates" : [
{
"template_1" : {
"match" : "multi*",
"mapping" : {
"type" : "{dynamic_type}",
"index" : "analyzed",
"fields" : {
"org" : {"type": "{dynamic_type}", "index" : "not_analyzed"}
}
}
}
},
{
"template_2" : {
"match" : "*",
"match_mapping_type" : "string",
"mapping" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
]
}
}
以上对所有以muti开头的field都设置成了multifield类型(template1),所有string类型的field都应用not_analyzed选项。
mapping中的具体属性不再具体介绍:比如{dynamic_type}这个变量是指动态detect出来的类型,比如date等。
完全通用的设置也可以应用:
{
"person" : {
"dynamic_templates" : [
{
"store_generic" : {
"match" : "*",
"mapping" : {
"store" : true
}
}
}
]
}
}
以上说明,所有的字段都stored。
注意,一般以上的通用设置要放在template list最后,因为如果多个mapping匹配到同一个field,则只有第一个会被应用,也就是越往前的优先级越高。
5:nested object type
nested object type跟object type类似,不同点在于:一个object 组成的array 是扁平的,而一个nested object组成的array每一个object是独立的。比如:
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
},
]
}
以上document中,user如果是一个object type,则存储是这样的:
{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}
丧失了first 跟 last的关系。
而如果user是一个nested object type,则存储是这样的:
{
"user.first" : "alice",
"user.last" : "white"
}
{
"user.first" : "john",
"user.last" : "smith"
}
{
"group" : "fans"
}
显然每一个object作为单独的一个document存储了,维持了object中field之间的关系。
因此,如果查询alice AND smith是不会有匹配结果的。
对nested object的查询可以使用nested query或者nested filter。
nested object的显式mapping如下定义:
{
"type1" : {
"properties" : {
"users" : {
"type" : "nested",
"properties": {
"first" : {"type": "string" },
"last" : {"type": "string" }
}
}
}
}
}
也许,我们想要我们的object既要是nested object,也要flat object,则可以如下设置:
{
"type1" : {
"properties" : {
"users" : {
"type" : "nested",
"include_in_parent": true,
"properties": {
"first" : {"type": "string" },
"last" : {"type": "string" }
}
}
}
}
}
使用include_in_parent选项。实际存储如下:
{
"user.first" : "alice",
"user.last" : "white"
}
{
"user.first" : "john",
"user.last" : "smith"
}
{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}
nested object可能还会包含nested object,include_in_parent只会设置到其直接parent上,如果设置到最顶层root parent上,则需要使用include_in_root选项。
在内部,nested object是作为额外的文档被索引的,但是,因为可以确保存储在同一个block上,因此,在与parent docs进行join时速度也非常快。
在针对index执行操作时(比如执行一个match_all类型的查询)这种内部的nested document会被自动隐藏,但是在执行nested query的时候,这种关联关系就显现出来了。
因为nested object对parent doc总是被掩藏的,因此nested docs不能在nested query范围之外被访问。例如:在nested object内部field的store属性可以enable,但是却不能检索它们,因此,stored field是在nested query范围之外fetch的。
_source field也是跟parent document相关联的,因此可以通过source获取到nested object的field 值并返回。
6:ip type
存储ipv4地址的类型。
7:geo point type and geo shape type
存储地理位置的类型。
point支持维度在前,精度在后格式。可以为数组,字符串等。
shape定义了矩形,多边形,三角形等。
其中请注意精度设置。
8:attachment type
定义了附件的类型,比如doc,pdf等,内容是用base64编码的。需要插件的支持,底层使用的是apache的tika。