字段数据类型(二)

2019-09-08 23:03发布

(一)别名数据类型alias

alias映射为索引中字段的替代名称。别名可用于代替搜索请求中的目标字段。

PUT trips
{
  "mappings": {
    "properties": {
      "distance": {
        "type": "long"
      },
      "route_length_miles": {
        "type": "alias",
        "path": "distance" #目标字段的路径。请注意,这必须是完整路径,包括任何父对象(例如object1.object2.field)。
      },
      "transit_mode": {
        "type": "keyword"
      }
    }
  }
}

GET _search
{
  "query": {
    "range" : {
      "route_length_miles" : {
        "gte" : 39
      }
    }
  }
}

別名可以通过通配符匹配:

GET trips/_field_caps?fields=route_*,transit_mode

别名的目标有一些限制:

  • 目标必须是具体字段,而不是对象或其他字段别名。
  • 目标字段必须在创建别名时存在。
  • 如果定义了嵌套对象,则字段别名必须与其目标具有相同的嵌套范围。

此外,字段别名只能有一个目标。这意味着无法使用字段别名来查询单个子句中的多个目标字段。

可以通过映射更新更改别名指向新目标。有个限制是任何存储的过滤器查询包含该字段别名,它们仍将引用其原始目标。

不支持的APIs

不支持写入字段别名:尝试在索引或更新请求中使用别名将导致失败。同样,别名不能用作copy_to多字段的目标或在多字段multi-fields中使用。

由于文档source中不存在别名,因此在执行source过滤时不能使用别名。例如,以下请求将返回空结果_source

GET /_search
{
  "query" : {
    "match_all": {}
  },
  "_source": "route_length_miles"
}

目前,只有search 和 field capabilities APIs 才会接受并解析字段别名。

(二)数组arrays

在Elasticsearch中,没有专用的array数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值必须具有相同的数据类型。例如:

  • 字符串数组:[ "one""two"]
  • 一个整数数组:[ 12]
  • 数组的数组:[ 123]],这是相当于[ 123]
  • 一个对象数组:[ { "name": "Mary", "age": 12 }{ "name": "John", "age": 10 }]
对象数组不能像您期望的那样工作:您无法独立于数组中的其他对象查询每个对象。如果您需要能够执行此操作,则应使用nested数据类型而不是object数据类型。这在嵌套中有更详细的解释。

动态添加字段时,数组中的第一个值确定字段类型。所有后续值必须具有相同的数据类型,或者必须至少可以将后续值强制转换为相同的数据类型。

支持混合使用数据类型的数组:[ 10"some string"]

数组可以包含null值,这些值可以由已配置的null_value值替换,也可以完全被忽略。空数组 []被视为 没有值的字段。

没有任何东西需要预先配置才能在文档中使用数组,它们是开箱即用的:

PUT my_index/_doc/1
{
  "message": "some arrays in this document...",
  "tags":  [ "elasticsearch", "wow" ],   # 被动态的设置为string类型
  "lists": [                             # Ojbect类型
    {
      "name": "prog_list",
      "description": "programming list"
    },
    {
      "name": "cool_list",
      "description": "cool stuff list"
    }
  ]
}

PUT my_index/_doc/2 
{
  "message": "no arrays in this document...",
  "tags":  "elasticsearch",
  "lists": {                        
    "name": "prog_list",
    "description": "programming list"
  }
}

GET my_index/_search
{
  "query": {
    "match": {
      "tags": "elasticsearch"     # 上面两个文档都会被查询到
    }
  }
}

(三)二进制数据类型

binary类型接受二进制值作为 Base64编码的字符串。默认情况下不存储该字段,并且不可搜索(Base64编码的二进制值不得包含嵌入的换行符\n):

PUT my_index
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "blob": {
        "type": "binary"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "name": "Some binary blob",
  "blob": "U29tZSBiaW5hcnkgYmxvYg==" 
}

binary字段的参数

binary字段接受以下参数:

doc_values

字段是否存储在磁盘上,以便以后可以用于排序,聚合或脚本编写?接受true 或false(默认)。

store

字段值是否应该与_source字段分开存储和检索。接受truefalse (默认)。

(四)布尔数据类型

布尔字段接受JSON truefalse值,但也可以接受被解释为true或false的字符串:

假:false, "false"

真:true, "true"

例如

PUT my_index
{
  "mappings": {
    "properties": {
      "is_published": {
        "type": "boolean"
      }
    }
  }
}

POST my_index/_doc/1
{
  "is_published": "true"   #字符串true
}

POST my_index/_doc/2
{
  "is_published": true
}

GET my_index/_search
{
  "query": {
    "term": {
      "is_published": true   # Json true or string "true"
    }
  }
}

搜索结果如下:

 "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "is_published" : "true"
        }
      },
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.18232156,
        "_source" : {
          "is_published" : true
        }
      }
    ]

聚合像是terms aggregation对结果中的key使用1和0和对key_as_string使用字符串"true", "false"。在脚本中使用的布尔字段,返回1和0:

POST my_index/_doc/1
{
  "is_published": true
}

POST my_index/_doc/2
{
  "is_published": false
}

GET my_index/_search
{
  "aggs": {
    "publish_state": {
      "terms": {
        "field": "is_published"
      }
    }
  },
  "script_fields": {
    "is_published": {
      "script": {
        "lang": "painless",
        "source": "doc['is_published'].value"
      }
    }
  }
}

以上返回(部分结果):

"aggregations" : {
    "publish_state" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 0,
          "key_as_string" : "false",
          "doc_count" : 1
        },
        {
          "key" : 1,
          "key_as_string" : "true",
          "doc_count" : 1
        }
      ]
    }
  }

boolean字段接受以下参数:

boost

接受浮点数,默认为1.0

doc_values

字段是否存储在磁盘上,以便以后可以用于排序,聚合或脚本编写?接受true (默认)或false

index

这个领域应该可以搜索吗?接受true(默认)和false

null_value

接受上面列出的任何真或假值。该值替换任何显式null值。默认为null,表示该字段被视为缺失。

store

字段值是否应该与_source字段分开存储和检索。接受truefalse (默认)。

(五)日期数据类型

JSON没有日期数据类型,因此Elasticsearch中的日期可以是:

  • 包含格式化日期的字符串,例如"2015-01-01""2015/01/01 12:10:30"
  • 一个 long number长数字milliseconds-since-the-epoch
  • 一个integer整数seconds-since-the-epoch.

在内部,日期转换为UTC(如果指定了时区)并存储为 a long number representing milliseconds-since-the-epoch

日期查询在内部转换为范围查询,聚合和存储字段的结果将转换回字符串,具体取决于与字段关联的日期格式。

日期将始终呈现为字符串。

可以自定义日期格式,但如果未指定format,则使用默认格式:

"strict_date_optional_time||epoch_millis"

这意味着它将接受带有可选时间戳的日期,这些时间戳符合支持的格式strict_date_optional_time 或者milliseconds-since-the-epoch

例如:

PUT my_index
{
  "mappings": {
    "properties": {
      "date": {
        "type": "date"   #使用默认format
      }
    }
  }
}

PUT my_index/_doc/1
{ "date": "2015-01-01" }    

PUT my_index/_doc/2
{ "date": "2015-01-01T12:10:30Z" } 

PUT my_index/_doc/3
{ "date": 1420070400001 } 

GET my_index/_search
{
  "sort": { "date": "asc"}   # sort返回的值都是以毫秒为单位
}

多种日期格式

可以通过将它们||作为分隔符分隔来指定多种格式。将依次尝试每种格式,直到找到匹配的格式。第一种格式将用于将毫秒 值转换回字符串。

PUT my_index
{
  "mappings": {
    "properties": {
      "date": {
        "type":   "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

date字段接受以下参数:

boost

接受浮点数,默认为1.0

doc_values

字段是否存储在磁盘上,以便以后可以用于排序,聚合或脚本编写?接受true (默认)或false

format

可以解析的日期格式。默认为 strict_date_optional_time||epoch_millis

locale

默认是 ROOT语言环境

ignore_malformed

如果true,错误的数字被忽略。如果false(默认),格式错误的数字会抛出异常并拒绝整个文档。

index

这个领域应该可以搜索吗?接受true(默认)和false

null_value

接受其中一个配置的日期值format作为替换任何显式null值的字段。默认为null,表示该字段被视为缺失。

store

字段值是否应该与_source字段分开存储和检索。接受truefalse (默认)。

(六)日期纳秒数据类型

此数据类型是数据类型的补充date。然而,两者之间存在重要区别。现有date数据类型以毫秒分辨率存储日期。该date_nanos数据类型存储在纳秒的分辨率,这限制了它的范围内的日期从大约1970至2262年,日期以long整形纳秒存储。

在纳秒上的查询在内部转换为范围查询,且聚合和存储字段的结果将根据与该字段关联的日期格式转换回字符串。

可以自定义日期格式,但如果未指定format,则使用默认格式:

“strict_date_optional_time || epoch_millis”

这意味着它将接受带有可选时间戳的日期,这些日期符合支持的格式, strict_date_optional_time

例如:

PUT my_index?include_type_name=true
{
  "mappings": {
    "_doc": {
      "properties": {
        "date": {
          "type": "date_nanos" 
        }
      }
    }
  }
}

PUT my_index/_doc/1
{ "date": "2015-01-01" } 

PUT my_index/_doc/2
{ "date": "2015-01-01T12:10:30.123456789Z" } 

PUT my_index/_doc/3
{ "date": 1420070400 } 

GET my_index/_search
{
  "sort": { "date": "asc"}   # 以纳秒返回
}

GET my_index/_search
{
  "script_fields" : {
    "my_field" : {
      "script" : {
        "lang" : "painless",
        "source" : "doc['date'].date.nanos" 
      }
    }
  }
}

GET my_index/_search
{
  "docvalue_fields" : [
    {
      "field" : "my_ip_field",
      "format": "strict_date_time" 
    }
  ]
}

限制

即使使用date_nanos字段,聚合仍然是毫秒级的分辨率 。

(七)地理点数据类型geo_point

有四种方法可以指定地理点,如下所示

PUT my_index
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "text": "Geo-point as an object",
  "location": { 
    "lat": 41.12,                 # 对象
    "lon": -71.34
  }
}

PUT my_index/_doc/2
{
  "text": "Geo-point as a string",
  "location": "41.12,-71.34"     #字符串
}

PUT my_index/_doc/3
{
  "text": "Geo-point as a geohash",
  "location": "drm3btev3e86"      #geohash
}

PUT my_index/_doc/4
{
  "text": "Geo-point as an array",
  "location": [ -71.34, 41.12 ]  #数组
}

GET my_index/_search
{
  "query": {
    "geo_bounding_box": { 
      "location": {
        "top_left": {
          "lat": 42,
          "lon": -72
        },
        "bottom_right": {
          "lat": 40,   #latitude纬度
          "lon": -74   #longitude经度
        }
      }
    }
  }
}
字符串地理点的排序方式为lat,lon(纬度,经度),而数组地理点的排序顺序为:lon,lat

geo_point字段接受以下参数:

ignore_malformed

如果true,格式错误的地理点被忽略。如果false(默认),格式错误的地理点会抛出异常并拒绝整个文档。

ignore_z_value

如果true(默认)将接受三个维度点(存储在源中),但仅索引纬度和经度值; 第三个维度被忽略了。如果false包含任何超过纬度和经度(二维)值的地理点抛出异常并拒绝整个文档。

null_value

接受一个替换任何显式null值的geopoint 值。默认为null,表示该字段被视为缺失。

(八)IP数据类型

一个ip字段可以索引/存储IPv4或 IPv6的地址。

PUT my_index
{
  "mappings": {
    "properties": {
      "ip_addr": {
        "type": "ip"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "ip_addr": "192.168.1.1"
}

GET my_index/_search
{
  "query": {
    "term": {
      "ip_addr": "192.168.0.0/16"
    }
  }
}


GET my_index/_search
{
  "query": {
    "term": {
      "ip_addr": "2001:db8::/48"
    }
  }
}


GET my_index/_search
{
  "query": {
    "query_string" : {
      "query": "ip_addr:\"2001:db8::/48\""  #还要注意冒号是query_string查询的特殊字符 ,因此需要转义ipv6地址。
    }
  }
}

ip字段接收的参数:

boost, doc_values, index, null_value, store

(九)Join数据类型

join数据类型是创建相同的索引文件中的父/子关系的特殊字段。该relations部分定义了文档中的一组可能的关系,每个关系是父名称和子名称。父/子关系可以定义如下:

PUT my_index
{
  "mappings": {
    "properties": {
      "my_join_field": {         # 字段的名称
        "type": "join",
        "relations": {
          "question": "answer"   # question是answer的父级
        }
      }
    }
  }
}

要使用连接索引文档,必须在source中提供关系的名称和可选文档的父级。例如,以下示例创建两个parent文档:

PUT my_index/_doc/1?refresh
{
  "text": "This is a question",
  "my_join_field": {
    "name": "question" 
  }
}

PUT my_index/_doc/2?refresh
{
  "text": "This is another question",
  "my_join_field": {
    "name": "question"
  }
}

索引父文档时,可以选择仅指定关系的名称:

PUT my_index/_doc/1?refresh
{
  "text": "This is a question",
  "my_join_field": "question" 
}

PUT my_index/_doc/2?refresh
{
  "text": "This is another question",
  "my_join_field": "question"
}

索引子文档时,必须在中添加关系的名称以及父文档的ID _source

所有父子文档需要在同一个分片中,所以必须使用父文档id路由子文档

例如,以下示例显示如何索引两个child文档:

PUT my_index/_doc/3?routing=1&refresh   # routing是必须的,因为父子文档必须在同一个分片中
{
  "text": "This is an answer",
  "my_join_field": {
    "name": "answer",        # answer 是此文档的连接名称
    "parent": "1"            # 此子文档的父文档ID
  }
}

PUT my_index/_doc/4?routing=1&refresh
{
  "text": "This is another answer",
  "my_join_field": {
    "name": "answer",
    "parent": "1"
  }
}

每个联接字段has_childhas_parent查询都会为查询性能添加重要开销,join字段有意义的唯一情况是,如果您的数据包含一对多关系,其中一个实体明显超过另一个实体。这种情况的一个例子是产品的用例和这些产品的报价,报价数量明显大于产品数量。

限制:

  • join每个索引只允许一个字段映射。
  • 父文档和子文档必须在同一个分片上编制索引。这意味着在获取删除更新 子文档时需要提供相同的routing值 。
  • 元素可以有多个子元素,但只有一个父元素。
  • 可以向现有join字段添加新关系。
  • 也可以将子项添加到现有元素,但仅当元素已经是父元素时才可以。

查询:

GET my_index/_search
{
  "query": {
    "match_all": {}
  },
  "sort": ["_id"]
}

查询和聚合:

GET my_index/_search
{
  "query": {
    "parent_id": {           # 固定写法
      "type": "answer",   
      "id": "1"              # 查询parentID是1的answer文档
    }
  },
  "aggs": {
    "parents": {
      "terms": {
        "field": "my_join_field#question",     # 在parent id字段上聚合
        "size": 10
      }
    }
  },
  "script_fields": {
    "parent": {
      "script": {
         "source": "doc['my_join_field#question']" 
      }
    }
  }
}

GET /my_index/_search
{
    "query": {
        "has_parent" : {
            "parent_type" : "question",  # 必须
            "query" : {                # 必须
                "term" : {
                    "text" : {
                        "value" : "this is"
                    }
                }
            }
        }
    }
}

GET /_search
{
    "query": {
        "has_child" : {
            "type" : "answer",  # 必须
            "query" : {        # 必须
                "match_all" : {}
            },
            "max_children": 10,
            "min_children": 2,
            "score_mode" : "min"
        }
    }
}

单个父项定义多个子项:

PUT my_index
{
  "mappings": {
    "properties": {
      "my_join_field": {
        "type": "join",
        "relations": {
          "question": ["answer", "comment"]  
        }
      }
    }
  }
}

多级联接

不建议使用多级关系来复制关系模型。在内存和计算方面,每个级别的关系在查询时增加了开销。如果您关心性能,则应该对数据进行去标准化。
PUT my_index
{
  "mappings": {
    "properties": {
      "my_join_field": {
        "type": "join",
        "relations": {
          "question": ["answer", "comment"],  
          "answer": "vote" 
        }
      }
    }
  }
}


PUT my_index/_doc/3?routing=1&refresh   # routing指向最上层ID
{
  "text": "This is a vote",
  "my_join_field": {
    "name": "vote",
    "parent": "2"      #指向父级ID
  }
}

以上关系如下:

  question
    /    \
   /      \
comment  answer
           |
           |
          vote

(十)关键字数据类型Keyword

用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。

它们通常用于过滤,排序,和聚合。关键字字段只能按其确切值进行搜索。

如果您需要索引电子邮件正文或产品说明等全文内容,则可能应该使用text字段。

以下是关键字字段的映射示例:

PUT my_index
{
  "mappings": {
    "properties": {
      "tags": {
        "type":  "keyword"
      }
    }
  }
}

keyword字段接受以下参数:

boostdoc_values, eager_global_ordinals, fields, ignore_above, index, index_options, norms, null_value, store,similarity,normalizer,split_queries_on_whitespace

(十一)嵌套数据类nested

该nested类型是特殊的object数据类型,它允许对象数组以可以彼此独立查询的方式进行索引。

Elasticsearch将对象层次结构扁平化为一个简单的字段名称和值列表。例如,以下文件:

PUT my_index/_doc/1
{
  "group" : "fans",
  "user" : [       # user字段将动态添加为类型字段object。
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

将在内部转换为像这样的文档:

{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}

user.first和user.last字段被转化为多值字段,alice和white之间的关联丢失了。此文档将错误地匹配查询alice AND smith(实际上Alic的last并不是Smith):

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [        
        { "match": { "user.first": "Alice" }},  
        { "match": { "user.last":  "Smith" }}
      ]
    }
  }
}

使用nested字段映射对象数组

如果需要索引对象数组并保持数组中每个对象的独立性,则应使用nested数据类型而不是 object数据类型。在内部,嵌套对象索引每个对象阵列作为一个多带带的隐藏文件中,这意味着每个嵌套对象可以使用nested查询独立于其它进行查询:

PUT my_index
{
  "mappings": {
    "properties": {
      "user": {
        "type": "nested" 
      }
    }
  }
}

PUT my_index/_doc/1
{
  "group" : "fans",
  "user" : [
    {
      "first" : "John",
      "last" :  "Smith"
    },
    {
      "first" : "Alice",
      "last" :  "White"
    }
  ]
}

GET my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},  #Alice和 Smith 不在同一个nested object.故查询不匹配
            { "match": { "user.last":  "Smith" }} 
          ]
        }
      }
    }
  }
}

GET my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          "must": [
            { "match": { "user.first": "Alice" }},
            { "match": { "user.last":  "White" }} 
          ]
        }
      },
      "inner_hits": { 
        "highlight": {
          "fields": {
            "user.first": {}
          }
        }
      }
    }
  }
}
由于嵌套文档被索引为多带带的文档,因此只能在nested查询

nested映射和对象限制

如前所述,每个嵌套对象都被索引为多带带文档。继续上面的示例,如果我们索引包含100个user对象的单个文档,则将创建101个Lucene文档 - 一个用于父文档,一个用于每个嵌套对象。由于与nested映射相关的资源消耗,Elasticsearch将设置以防止出现性能问题:

index.mapping.nested_fields.limit

nested只有在特殊情况下才需要使用该类型,即需要相互独立地查询对象数组。为了防止设计不良的映射,此设置限制了每个索引的nested类型数。在我们的示例中,user映射将计为1。如果还有一个nested字段则加一,以此类推,默认为50。

index.mapping.nested_objects.limit

此设置限制单个文档可能包含在所有nested类型中的嵌套对象的数量, 以防止在文档包含太多嵌套对象时出现内存不足错误。为了说明设置是如何工作的,请说我们在 上面的示例映射中添加了另一个nested类型comments。然后,对于每个文档, 它包含usercomment对象的组合数量必须低于限制。默认为10000。

有关这些设置的其他背景信息(包括有关其默认值的信息)可在“设置”中找到,以防止映射爆炸

(十二)数字数据类型

支持以下数字类型:

long

带符号的64位整数,其最小值为,最大值为。-263263-1

integer

带符号的32位整数,其最小值为,最大值为。-231231-1

short

带符号的16位整数,其最小值为-32,768,最大值为32,767

byte

带符号的8位整数,其最小值为-128,最大值为127

double

双精度64位IEEE 754浮点数,限制为有限值。

float

单精度32位IEEE 754浮点数,限制为有限值。

half_float

半精度16位IEEE 754浮点数,限制为有限值。

scaled_float

A floating point number that is backed by a long, scaled by a fixed doublescaling factor.

登录 后发表评论
0条评论
还没有人评论过~