一、文档字段介绍
1、核心数据类型
#字符串类型:string,字符串类还可被分为text和keyword类型,如果我们让es自动映射数据,那么es会把字符串定义为text,并且还加了一个keyword类型字段。
text文本数据类型,用于索引全文值的字段。使用文本数据类型的字段,它们会被分词,在索引之前将字符串转换为单个术语的列表(倒排索引),分词过程允许ES搜索每个全文字段中的单个单词。什么情况适合使用text,只要不具备唯一性的字符串一般都可以使用text。
keyword关键字数据类型,用于索引结构化内容的字段。使用keyword类型的字段,其不会被分析,给什么值就原封不动地按照这个值索引,所以关键字字段只能按其确切值进行搜索。什么情况下使用keyword,具有唯一性的字符串,例如:电子邮件地址、MAC地址、身份证号、状态代码...等等。
# 数字型数据类型:long、integer、short、byte、double、float
# 日期类型:date
# 布尔类型:boolean
2、复杂数据类型
# 数组:无需专门的数据类型
# 对象数据类型:单独的JSON对象
# 嵌套数据类型:nested,关于JSON对象的数组
3、地理数据类型
# 地理点数据类型
# 地理形状数据类型
4、专门数据类型:
# IPv4数据类型
# 单词计数数据类型token_count
我们结合前面的映射来看看:
创建一个新的索引:
PUT /open-soft
显式映射:
PUT /open-soft/_mapping
{
"properties": {
"corp": {
"type": "text"
},
"lang": {
"type": "text"
},
"name": {
"type": "text"
}
}
}
索引或者说入库一个文档,注意这个文档的字段,比我们显示映射的字段要多个star字段:
PUT /open-soft/_doc/1
{
"name": "Apache Hadoop",
"lang": "Java",
"corp": "Apache",
"stars": 200
}
通过GET /open-soft/_mapping,我们可以看到es自动帮我们新增了stars这个字段。
修改映射,增加一个新的字段:
PUT /open-soft/_mapping
{
"properties": {
"year": {
"type": "integer"
}
}
}
5、数组
不需要特殊配置,一个字段如果被配置为基本数据类型,就是天生支持数组类型的。任何字段都可以有0个或多个值,但是在一个数组中数据类型必须一样。比如:
PUT /open-soft/_doc/2
{
"name": [
"Apache Activemq",
"Activemq Artemis"
],
"lang": "Java",
"corp": "Apache",
"stars": [
500,
200
]
}
是没问题的,但是如果:
PUT /open-soft/_doc/3
{
"name": ["Apache Kafka"],
"lang": "Java",
"corp": "Apache",
"stars":[500,"kafka"]
}
则会出错。
6、对象
JSON文档是有层次结构的,一个文档可能包含其他文档,如果一个文档包含其他文档,那么该文档值是对象类型,其数据类型是对象。当然ElasticSearch中是没有所谓对象类型的,比如:
PUT /open-soft/_doc/object
{
"name": [
"Apache ShardingSphere"
],
"lang": "Java",
"corp": "JingDong",
"stars": 400,
"address": {
"city": "BeiJing",
"country": "亦庄"
}
}
查询结构映射:
get /open-soft/_mapping
返回结果:
{
"open-soft" : {
"mappings" : {
"properties" : {
"address" : {
"properties" : {
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"country" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
},
"corp" : {
"type" : "text"
},
"lang" : {
"type" : "text"
},
"name" : {
"type" : "text"
},
"stars" : {
"type" : "long"
},
"year" : {
"type" : "integer"
}
}
}
}
}
对象类型可以在定义索引的映射关系时进行指定。
7、多数据类型
如果说数组允许你使用同一个设置索引多项数据,那么多数据类型允许使用不同的设置,对同一项数据索引多次。带来的好处就是可以同一文本有多种不同的索引方式,比如一个字符串类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。我们可以看到es的动态映射生成的字段类型里,往往字符串类型都使用了多数据类型。当然,我们一样也可以自己定义:
PUT /open-soft/_mapping
{
"properties": {
"name": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
},
"length": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
在上面的代码里,我们使用"fields"就把name字段扩充为多字段类型,为name新增了两个子字段raw和length,raw设置类型为keyword,length设置类型为 token_count,告诉es这个字段在保存还需要做词频统计。通过fields字段设置的子字段raw和length,在我们添加文档时,并不需要单独设置值,他们name共享相同的值,只是es会以不同的方式处理字段值。
同样在检索文档的时候,它们也不会显示在结果中,所以它们一般都是在检索中以查询条件的形式出现,以减少检索时的性能开销。
二、字段参数
在上面的代码里出现了analyzer这个词,这是什么?这个叫字段参数,和type一样,可以用来对字段进行配置。常用的字段参数和作用如下:analyzer指定分词器。elasticsearch是一款支持全文检索的分布式存储系统,对于text类型的字段,首先会使用分词器进行分词,然后将分词后的词根一个一个存储在倒排索引中,后续查询主要是针对词根的搜索。
1、analyzer
该参数可以在每个查询、每个字段、每个索引中使用,其优先级如下(越靠前越优先):
1)字段上定义的分词器
2)索引配置中定义的分词器
3)默认分词器(standard)
2、normalizer
规范化,主要针对keyword类型,在索引该字段或查询字段之前,可以先对原始数据进行一些简单的处理,然后再将处理后的结果当成一个词根存入倒排索引中,默认为null,比如:
PUT index
{
"settings": {
"analysis": {
"normalizer": {
"my_normalizer": { // 1
"type": "custom",
"char_filter": [],
"filter": ["lowercase", "asciifolding"] // 2
}
}
}
},
"mappings": {
"_doc": {
"properties": {
"foo": {
"type": "keyword",
"normalizer": "my_normalizer" // 3
}
}
}
}
}
代码 1:首先在settings中的analysis属性中定义normalizer。
代码 2:设置标准化过滤器,示例中的处理器为小写、asciifolding。
代码 3:在定义映射时,如果字段类型为keyword,可以使用normalizer引用定义好的normalizer
3、boost
权重值,可以提升在查询时的权重,对查询相关性有直接的影响,其默认值为1.0。其影响范围为词根查询(team query),对前缀、范围查询。5.0 版本后已废止。
4、coerce
数据不总是我们想要的,由于在转换JSON body为真正JSON的时候,整型数字5有可能会被写成字符串"5"或者浮点数5.0,这个参数可以将数值不合法的部分去除。默认为 true。
例如:将字符串会被强制转换为整数、浮点数被强制转换为整数。
例如存在如下字段类型:
"number_one": {
"type": "integer"
}
声明number_one字段的类型为数字类型,那是否允许接收“6”字符串形式的数据呢?因为在JSON中,“6”用来赋给int类型的字段,也是能接受的,默认coerce为true,表示允许这种赋值,但如果coerce 设置为false,此时es只能接受不带双引号的数字,如果在coerce=false时,将“6”赋值给number_one时会抛出类型不匹配异常。
5、copy_to
copy_to参数允许您创建自定义的_all字段。换句话说,多个字段的值可以复制到一个字段中。
例如,first_name和last_name字段可以复制到full_name字段如下:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"first_name": {
"type": "text",
"copy_to": "full_name"
},
"last_name": {
"type": "text",
"copy_to": "full_name"
},
"full_name": {
"type": "text"
}
}
}
}
}
表示字段 full_name 的值来自first_name + last_name。
关于copy_to重点说明:
1)字段的复制是原始值。
2)同一个字段可以复制到多个字段,写法如下:“copy_to”: [ “field_1”,“field_2” ]
6、doc_values
Doc values的存在是因为倒排索引只对某些操作是高效的。倒排索引的优势在于查找包含某个项的文档,而对于从另外一个方向的相反操作并不高效,即:确定哪些项是否存在单个文档里,聚合需要这种次级的访问模式。
对于以下倒排索引:
如果我们想要获得所有包含brown的文档的词的完整列表,倒排索引是根据词项来排序的,所以我们首先在词项列表中找到brown,然后扫描所有列,找到包含brown的文档。我们可以快速看到Doc_1和Doc_2包含brown这个token。然后,对于聚合部分,我们需要找到Doc_1和Doc_2里所有唯一的词项。用倒排索引做这件事情代价很高:我们会迭代索引里的每个词项并收集Doc_1和Doc_2列里面token。这很慢而且难以扩展:随着词项和文档的数量增加,执行时间也会增加。
Doc values通过转置两者间的关系来解决这个问题。倒排索引将词项映射到包含它们的文档,doc values 将文档映射到它们包含的词项:
Doc Terms
--------------------------------------------------------------
Doc_1 | brown, dog, fox, jumped, lazy, over, quick, the
Doc_2 | brown, dogs, foxes, in, lazy, leap, over, quick, summer
Doc_3 | dog, dogs, fox, jumped, over, quick, the
--------------------------------------------------------------
当数据被转置之后,想要收集到Doc_1和Doc_2的唯一token会非常容易。获得每个文档行,获取所有的词项,然后求两个集合的并集。
doc_values缺省是true,即是开启的,并且只适用于非text类型的字段。
7、dynamic
是否允许动态的隐式增加字段。在执行index api或更新文档API时,对于_source字段中包含一些原先未定义的字段采取的措施,根据dynamic的取值,会进行不同的操作:
true默认值,表示新的字段会加入到类型映射中。
false新的字段会被忽略,即不会存入_souce字段中,即不会存储新字段,也无法通过新字段进行查询。
strict会显示抛出异常,需要新使用 put mapping api 先显示增加字段映射。
8、enabled
是否建立索引,默认情况下为true,es会尝试为你索引所有的字段,但有时候某些类型的字段,无需建立索引,只是用来存储数据即可。也就是说,ELasticseaech 默认会索引所有的字段,enabled设为false的字段,elasicsearch会跳过字段内容,该字段只能从_source中获取,但是不可搜。只有映射类型(type)和 object类型的字段可以设置enabled属性。
9、eager_global_ordinals
表示是否提前加载全局顺序号。Global ordinals是一个建立在doc values和fielddata基础上的数据结构, 它为每一个精确词按照字母顺序维护递增的编号。
每一个精确词都有一个独一无二的编号并且精确词A小于精确词B的编号,Global ordinals只支持keyword和text型字段,在keyword字段中,默认是启用的而在text型字段中只有fielddata和相关属性开启的状态下才是可用的。
10、fielddata
为了解决排序与聚合,elasticsearch提供了doc_values属性来支持列式存储,但doc_values不支持text字段类型。因为text字段是需要先分析(分词),会影响doc_values列式存储的性能。
es为了支持text字段高效排序与聚合,引入了一种新的数据结构(fielddata),使用内存进行存储。默认构建时机为第一次聚合查询、排序操作时构建,主要存储倒排索引中的词根与文档的映射关系,聚合,排序操作在内存中执行。因此fielddata需要消耗大量的JVM堆内存。一旦fielddata加载到内存后,它将永久 存在。
通常情况下,加载fielddata是一个昂贵的操作,故默认情况下,text字段的字段默认是不开启fielddata机制。在使用fielddata之前请慎重考虑为什么要开启fielddata。
11、format
在 JSON 文档中,日期表示为字符串。Elasticsearch使用一组预先配置的格式来识别和解析这些字符串,并将其解析为long类型的数值(毫秒),支持自定义格式,也有内置格式。比如:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type":
"date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
elasticsearch 为我们内置了大量的格式,如下:
epoch_millis
时间戳,单位,毫秒,范围受限于 Java Long.MIN_VALUE 和 Long.MAX_VALUE。
epoch_second
时间戳,单位,秒,范围受限于 Java 的限制 Long.MIN_VALUE 并 Long.
MAX_VALUE 除以 1000(一秒中的毫秒数)。
date_optional_time 或者 strict_date_optional_time
日期必填,时间可选,其支持的格式如下:date-opt-time = date-element ['T' [time-element] [offset]]
date-element = std-date-element | ord-date-element | week-date-element
std-date-element = yyyy ['-' MM ['-' dd]]
ord-date-element = yyyy ['-' DDD]
week-date-element = xxxx '-W' ww ['-' e]
time-element = HH [minute-element] | [fraction]
minute-element = ':' mm [second-element] | [fraction]
second-element = ':' ss [fraction]
比如"yyyy-MM-dd"、"yyyyMMdd"、"yyyyMMddHHmmss"、
"yyyy-MM-ddTHH:mm:ss"、"yyyy-MM-ddTHH:mm:ss.SSS"、
"yyyy-MM-ddTHH:mm:ss.SSSZ"格式,不支持常用的"yyyy-MM-dd HH:mm:ss"等格式。
注意,"T"和"Z"是固定的字符。
tips:如果看到“strict_”前缀的日期格式要求,表示 date_optional_time 的
严格级别,这个严格指的是年份、月份、天必须分别以 4 位、2 位、2 位表示,
不足两位的话第一位需用 0 补齐。
basic_date
其格式表达式为 :yyyyMMdd
basic_date_time
其格式表达式为:yyyyMMdd’T’HHmmss.SSSZ
basic_date_time_no_millis
其格式表达式为:yyyyMMdd’T’HHmmssZ
basic_ordinal_date
4 位数的年 + 3 位(day of year),其格式字符串为 yyyyDDD
basic_ordinal_date_time
其格式字符串为 yyyyDDD’T’HHmmss.SSSZ
basic_ordinal_date_time_no_millis
其格式字符串为 yyyyDDD’T’HHmmssZ
basic_time
其格式字符串为 HHmmss.SSSZ
basic_time_no_millis
其格式字符串为 HHmmssZ
basic_t_time
其格式字符串为’T’HHmmss.SSSZ
basic_t_time_no_millis
其格式字符串为’T’HHmmssZ
basic_week_date其格式字符串为 xxxx’W’wwe,4 为年 ,然后用’W’, 2 位 week of year
(所在年里周序号) 1 位 day of week。
basic_week_date_time
其格式字符串为 xxxx’W’wwe’T’HH:mm:ss.SSSZ.
basic_week_date_time_no_millis
其格式字符串为 xxxx’W’wwe’T’HH:mm:ssZ.
date
其格式字符串为 yyyy-MM-dd
date_hour
其格式字符串为 yyyy-MM-dd’T’HH
date_hour_minute
其格式字符串为 yyyy-MM-dd’T’HH:mm
date_hour_minute_second
其格式字符串为 yyyy-MM-dd’T’HH:mm:ss
date_hour_minute_second_fraction
其格式字符串为 yyyy-MM-dd’T’HH:mm:ss.SSS
date_hour_minute_second_millis
其格式字符串为 yyyy-MM-dd’T’HH:mm:ss.SSS
date_time
其格式字符串为 yyyy-MM-dd’T’HH:mm:ss.SSS
date_time_no_millis
其格式字符串为 yyyy-MM-dd’T’HH:mm:ss
hour
其格式字符串为 HH
hour_minute
其格式字符串为 HH:mm
hour_minute_second
其格式字符串为 HH:mm:ss
hour_minute_second_fraction
其格式字符串为 HH:mm:ss.SSS
hour_minute_second_millis
其格式字符串为 HH:mm:ss.SSS
ordinal_date
其格式字符串为 yyyy-DDD,其中 DDD 为 day of year。
ordinal_date_time
其格式字符串为 yyyy-DDD‘T’HH:mm:ss.SSSZZ,其中 DDD 为 day of year。ordinal_date_time_no_millis
其格式字符串为 yyyy-DDD‘T’HH:mm:ssZZ
time
其格式字符串为 HH:mm:ss.SSSZZ
time_no_millis
其格式字符串为 HH:mm:ssZZ
t_time
其格式字符串为’T’HH:mm:ss.SSSZZ
t_time_no_millis
其格式字符串为’T’HH:mm:ssZZ
week_date
其格式字符串为 xxxx-'W’ww-e,4 位年份,ww 表示 week of year,e 表示 day
of week。
week_date_time
其格式字符串为 xxxx-'W’ww-e’T’HH:mm:ss.SSSZZ
week_date_time_no_millis
其格式字符串为 xxxx-'W’ww-e’T’HH:mm:ssZZ
weekyear
其格式字符串为 xxxx
weekyear_week
其格式字符串为 xxxx-'W’ww,其中 ww 为 week of year。
weekyear_week_day
其格式字符串为 xxxx-'W’ww-e,其中 ww 为 week of year,e 为 day of week。
year
其格式字符串为 yyyy
year_month
其格式字符串为 yyyy-MM
year_month_day
其格式字符串为 yyyy-MM-dd
12、ignore_above
ignore_above用于指定字段索引和存储的长度最大值,超过最大值的会被忽略。
13、ignore_malformed
ignore_malformed可以忽略不规则数据,对于login字段,有人可能填写的是date类型,也有人填写的是邮件格式。给一个字段索引不合适的数据类型发生异常,导致整个文档索引失败。如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引。
14、index
index属性指定字段是否索引,不索引也就不可搜索,取值可以为true或者false,缺省为true。
15、index_options
index_options控制索引时存储哪些信息到倒排索引中,用于搜索和突出显示目的。
doc:只存储文档编号
freqs:存储文档编号和词项频率。
positions:文档编号、词项频率、词项的位置被存储
offsets:文档编号、词项频率、词项的位置、词项开始和结束的字符位置都被存储。
16、fields
fields可以让同一文本有多种不同的索引方式,比如一个String类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。
17、norms
norms参数用于标准化文档,以便查询时计算文档的相关性。norms虽然对评分有用,但是会消耗较多的磁盘空间,如果不需要对某个字段进行评分,最好不要开启norms。
18、null_value
一般来说值为null的字段不索引也不可以搜索,null_value参数可以让值为null的字段显式的可索引、可搜索。
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"status_code": {
"type":
"keyword",
"null_value": "NULL"
}
}
}
}}
PUT my_index/my_type/1
{
"status_code": null
}
PUT my_index/my_type/2
{
"status_code": []
}
GET my_index/_search
{
"query": {
"term": {
"status_code": "NULL"
}
}
}
文档1可以被搜索到,因为status_code的值为null,文档2不可以被搜索到,因为status_code为空数组,但是不是null。
19、position_increment_gap
文本数组元素之间位置信息添加的额外值。
举例,一个字段的值为数组类型:"names": [ "John Abraham", "Lincoln Smith"]
为了区别第一个字段和第二个字段,Abraham 和 Lincoln 在索引中有一个间距,默认是 100。例子如下,这是查询”Abraham Lincoln”是查不到的:
PUT my_index/groups/1
{
"names": [ "John Abraham", "Lincoln Smith"]
}
GET my_index/groups/_search
{
"query": {
"match_phrase": {"names": {
"query": "Abraham Lincoln"
}
}
}
}
指定间距大于 10 0 可以查询到:
GET my_index/groups/_search
{
"query": {
"match_phrase": {
"names": {
"query": "Abraham Lincoln",
"slop": 101
}
}
}
}
想要调整这个值,在mapping中通过position_increment_gap参数指定间距即可。
20、properties
Object或者nested类型,下面还有嵌套类型,可以通过properties参数指定。
比如:
PUT my_index
{
"mappings": {
"my_type": {
"properties": {
"manager": {
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
},"employees": {
"type": "nested",
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
}
}
}
}
}
对应的文档结构:
PUT my_index/my_type/1
{
"region": "US",
"manager": {
"name": "Alice White",
"age": 30
},
"employees": [
{
"name": "John Smith",
"age": 34
},
{
"name": "Peter Brown",
"age": 26
}
]
}
21、search_analyzer
通常,在索引时和搜索时应用相同的分析器,以确保查询中的术语与反向索引中的术语具有相同的格式,如果想要在搜索时使用与存储时不同的分词器,则使用search_analyzer属性指定,通常用于ES实现即时搜索(edge_ngram)。
22、similarity
指定相似度算法,其可选值:BM25
当前版本的默认值,使用BM25算法。
classic:使用TF/IDF算法,曾经是es,lucene的默认相似度算法。
boolean:一个简单的布尔相似度,当不需要全文排序时使用,并且分数应该只基于查询条件是否匹配。布尔相似度为术语提供了一个与它们的查询boost相等的分数。
23、store
默认情况下,字段值被索引以使其可搜索,但它们不存储。这意味着可以查询字段,但无法检索原始字段值。通常这并不重要。字段值已经是_source字段的一部分,该字段默认存储。如果您只想检索单个字段或几个字段的值,而不是整个_source,那么这可以通过字段过滤上下文source filting context来实现。
在某些情况下,存储字段是有意义的。例如,如果您有一个包含标题、日期和非常大的内容字段的文档,您可能只想检索标题和日期,而不需要从大型_source 字段中提取这些字段,可以将标题和日期字段的store定义为true。
24、term_vector
Term vectors包含分析过程产生的索引词信息,包括:
索引词列表
每个索引词的位置(或顺序)
索引词在原始字符串中的原始位置中的开始和结束位置的偏移量。
term vectors会被存储,索引它可以作为一个特使的文档返回。
term_vector可取值:
- no不存储 term_vector 信息,默认值。
- yes 只存储字段中的值。
- with_positions 存储字段中的值与位置信息。
- with_offsets 存储字段中的值、偏移量
- with_positions_offsets 存储字段中的值、位置、偏移量信息。
三、元字段meta-fields
一个文档根据我们定义的业务字段保存有数据之外,它还包含了元数据字段(meta-fields)。元字段不需要用户定义,在任一文档中都存在,有点类似于数据库的表结构数据。在名称上有个显著的特征,都是以下划线“_”开头。我们可以看看:get /open-soft/_doc/1 大体分为五种类型:
身份(标识)元数据、索引元数据、文档元数据、路由元数据以及其他类型的元数据,当然不是每个文档这些元字段都有的。
1、身份(标识)元数据
_index:文档所属索引,自动被索引,可被查询,聚合,排序使用,或者脚本里访问。
_type:文档所属类型,自动被索引,可被查询,聚合,排序使用,或者脚本里访问。
_id:文档的唯一标识,建索引时候传入 ,不被索引,可通过_uid 被查询,脚本里使用,不能参与聚合或排序。
_uid:由_type和_id字段组成,自动被索引 ,可被查询,聚合,排序使用,或者脚本里访问,6.0.0 版本后已废止。
2、索引元数据
_all:自动组合所有的字段值,以空格分割,可以指定分器词索引,但是整个值不被存储,所以此字段仅仅能被搜索,不能获取到具体的值。6.0.0 版本后已废止。
_field_names:索引了每个字段的名字,可以包含null值,可以通过exists查询或missing查询方法来校验特定的字段。
3、文档元数据
_source:一个doc的原生的json数据,不会被索引,用于获取提取字段值,启动此字段,索引体积会变大,如果既想使用此字段又想兼顾索引体积,可以开启索引压缩。_source是可以被禁用的,不过禁用之后部分功能不再支持,这些功能包括:部分update api、运行时高亮搜索结果索引重建、修改mapping以及分词、索引升级debug查询或者聚合语句索引自动修复。
_size:整个_source字段的字节数大小,需要单独安装一个mapper-size插件才能展示。
4、路由元数据
_routing:一个doc可以被路由到指定的shard上。
5、其他
_meta:一般用来存储应用相关的元信息。
例如:
PUT /open-soft/_mapping
{
"_meta": {
"class": "cn.chj.User",
"version": {
"min": "1.0",
"max": "1.3"
}
}
}