可分析的字段的取值会被分析器经过Token过滤和字符过滤转换为一系列的索引词,举例来说, 字符串 “The quick Brown Foxes.” 依赖于所使用的分析器可以过滤分词为: quick, brown, fox. 它们会作为精确词被索引,这也使得在一段全文中检索这些关键字成为可能。
分析的过程不仅发生在索引的时候,在我们搜索的时候同样需要: 被检索的字符串需要经过同样的分析器分析,这样以来我们才可以在索引中检索同样被分析的全文。
Elasticsearch 预设了一系列的分析器,如果我们没有特别指定,Elasticsearch 会直接使用的预包装的分析器。
我们可以为每个索引、每次查询、每个字段指定分析器。Elasticsearch 按以下顺序查找分析器:
搜索的时候按以下顺序查找分析器:
最简单的方法为特定字段指定分析器实在它的映射中定义,例如:
PUT /my_index
{
"mappings": {
"_doc": {
"properties": {
"text": {
"type": "text", //使用默认标准分析器
"fields": {
"english": { //指明english分析器
"type": "text",
"analyzer": "english"
}
}
}
}
}
}
}
查看分词器
GET my_index/_analyze
{
"field": "text",
"text": "The quick Brown Foxes."
}
分析结果如下
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "" ,
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "" ,
"position": 1
},
{
"token": "brown",
"start_offset": 10,
"end_offset": 15,
"type": "" ,
"position": 2
},
{
"token": "foxes",
"start_offset": 16,
"end_offset": 21,
"type": "" ,
"position": 3
}
]
}
我们得到的精确词是[ the, quick, brown, foxes ]
接下来看看english分析器
GET my_index/_analyze
{
"field": "text.english",
"text": "The quick Brown Foxes."
}
结果如下
{
"tokens": [
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "" ,
"position": 1
},
{
"token": "brown",
"start_offset": 10,
"end_offset": 15,
"type": "" ,
"position": 2
},
{
"token": "fox",
"start_offset": 16,
"end_offset": 21,
"type": "" ,
"position": 3
}
]
}
得到的精确词是[ quick, brown, fox ]
对于keyword
类型的字段来说除了只会分析产生一个精确词以外normalizer 相当于analyzed。
normalizer 用在索引存储或者查询一个keyword
类型的字段之前标准化配置,比如把所有的字符转化为小写等。
配置索引
PUT index
{
"settings": {
"analysis": {
"normalizer": {
"my_normalizer": {
"type": "custom",
"char_filter": [],
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"_doc": {
"properties": {
"foo": {
"type": "keyword",
"normalizer": "my_normalizer"
}
}
}
}
}
存储文档
PUT index/_doc/1
{
"foo": "BÀR"
}
PUT index/_doc/2
{
"foo": "bar"
}
PUT index/_doc/3
{
"foo": "baz"
}
POST index/_refresh
精确词查询
GET index/_search
{
"query": {
"term": {
"foo": "BAR"
}
}
}
结果如下
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.2876821,
"hits": [
{
"_index": "index",
"_type": "_doc",
"_id": "2",
"_score": 0.2876821,
"_source": {
"foo": "bar"
}
},
{
"_index": "index",
"_type": "_doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"foo": "BÀR"
}
}
]
}
}
匹配查询
GET index/_search
{
"query": {
"match": {
"foo": "BAR"
}
}
}
结果如下
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.2876821,
"hits": [
{
"_index": "index",
"_type": "_doc",
"_id": "2",
"_score": 0.2876821,
"_source": {
"foo": "bar"
}
},
{
"_index": "index",
"_type": "_doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"foo": "BÀR"
}
}
]
}
}
同理,聚合查询的也会是标准化处理的字段
聚合查询
GET index/_search
{
"size": 0,
"aggs": {
"foo_terms": {
"terms": {
"field": "foo"
}
}
}
}
结果如下:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"foo_terms": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "bar",
"doc_count": 2
},
{
"key": "baz",
"doc_count": 1
}
]
}
}
}
我们可以通过指定一个boost值来控制每个查询子句的相对权重,该值默认为1。一个大于1的boost会增加该查询子句的相对权重。
索引映射定义的时候指定boost在elasticsearch5之后已经弃用。建议在查询的时候使用。
POST _search
{
"query": {
"match" : {
"title": {
"query": "quick brown fox",
"boost": 2
}
}
}
}
数据不总是我们想要的,由于在转换JSON body为真正JSON 的时候,整型数字5有可能会被写成字符串"5"或者浮点数5.0。
coerce属性可以用来清除脏数据。
例如:
举个例子:
定义索引映射
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"number_one": {
"type": "integer"
},
"number_two": {
"type": "integer",
"coerce": false
}
}
}
}
}
插入数据
PUT my_index/_doc/1
{
"number_one": "10"
}
插入结果:
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
number_one会插入整数10。
插入number_two数据
PUT my_index/_doc/2
{
"number_two": "10"
}
插入结果:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse [number_two]"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse [number_two]",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Integer value passed as String"
}
},
"status": 400
}
由于不能格式化,文档被拒绝。
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"
}
}
}
}
}
插入数据
PUT my_index/_doc/1
{
"first_name": "John",
"last_name": "Smith"
}
插叙数据
GET my_index/_search
{
"query": {
"match": {
"full_name": {
"query": "John Smith",
"operator": "and"
}
}
}
}
查询结果
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5753642,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 0.5753642,
"_source": {
"first_name": "John",
"last_name": "Smith"
}
}
]
}
}
很明显first_name 和 last_name 字段取值都被复制到 full_name 字段。
是为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"status_code": {
"type": "keyword"
},
"session_id": {
"type": "keyword",
"doc_values": false
}
}
}
}
}
默认情况下,字段可以自动添加到文档或者文档的内部对象,elasticsearc也会自动索引映射字段。
PUT my_index/_doc/1
{
"username": "johnsmith",
"name": {
"first": "John",
"last": "Smith"
}
}
GET my_index/_mapping
PUT my_index/_doc/2
{
"username": "marywhite",
"email": "[email protected]",
"name": {
"first": "Mary",
"middle": "Alice",
"last": "White"
}
}
GET my_index/_mapping
dynamic属性用于配置新字段添加时的映射动作,有三个取值:
例如:
PUT my_index
{
"mappings": {
"_doc": {
"dynamic": false,
"properties": {
"user": {
"properties": {
"name": {
"type": "text"
},
"social_networks": {
"dynamic": true,
"properties": {}
}
}
}
}
}
}
}
ELasticseaech默认会索引所有的字段,enabled设为false的字段,elasicsearch会跳过字段内容,该字段只能从_source中获取,但是不可搜。而且字段可以是任意类型。
例如:
新建索引,插入文档
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"name":{"enabled": false}
}
}
}
}
PUT my_index/_doc/1
{
"title": "test enabled",
"name":"test"
}
查看文档
GET my_index/_doc/1
结果
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "test enabled",
"name": "test"
}
}
搜索字段
GET my_index/_doc/_search
{
"query": {
"match": {
"name": "test"
}
}
}
结果
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 0,
"max_score": null,
"hits": []
}
}
大多数的字段默认会被索引,所以我们可以对他们检索,排序,聚合,甚至脚本操作, 然而,我们可能还需要与搜索不同的访问模式。
fielddata是text型的字段查询时使用一个内存型数据结构。该数据结构是根据需求第一次建立的,用于聚合、排序或脚本。它是通过从磁盘读取每个段的整个倒排索引、反转术语_文档关系并将结果存储在JVM堆的内存中来构建的。
fielddata在text型字段默认是关闭的。
fielddata会占用大量的堆内存,尤其是在加载的高基数的text型字段。 一旦 fielddata 被加载到堆里,它会一直存在于字段的生命周期中。此外,加载字段数据是一个昂贵的过程,这可能会导致用户体验延迟命中。这就是为什么默认情况下禁用fielddata 的原因。
如果尝试对文本字段上的脚本进行排序、聚合或访问值,则会遇到此异常。
默认情况下,字段数据在文本字段上禁用。对需要设置的text型字段设置fielddata = true,以便通过反转倒排索引来加载内存中的字段数据。注意,这可以使用大量的内存。
Global ordinals 是一个建立在 doc values 和 fielddata基础上的数据结构, 它为每一个精确词按照字母顺序维护递增的编号。每一个精确词都有一个独一无二的编号 并且 精确词 A 小于精确词 B的编号. Global ordinals 只支持 keyword and text 型字段,在 keyword 字段中, 默认是启用的 而在 text 型字段中 只有 fielddata 和相关属性开启的状态下才是可用的。
JSON 文档内部,日期可能展现为字段串的样式. ElasticSearch 内部会将日期数据转换为UTC,并存储为milliseconds-since-the-epoch的long型整数。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
}
}
}
}
超过 ignore_above 的字符串不会被索引。对于字符串数组, 如果单个子元素字符串超过了 ignore_above也不会被索引存储。
所有的字符串或者数组元素都会被在
_source
字段里,
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"message": {
"type": "keyword",
"ignore_above": 20 ,
"
}
}
}
}
}
数据插入
PUT my_index/_doc/1
{
"message": "Syntax error"
}
PUT my_index/_doc/2
{
"message": "Syntax error with some long stacktrace"
}
聚合查询
GET _search
{
"aggs": {
"messages": {
"terms": {
"field": "message"
}
}
}
}
结果
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "2",
"_score": 1,
"_source": {
"message": "Syntax error with some long stacktrace"
}
},
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"message": "Syntax error"
}
}
]
},
"aggregations": {
"messages": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Syntax error",
"doc_count": 1
}
]
}
}
}
有些时候你接受的数据可能不是你想要的,比如,有的时候接收到的login字段给的是date,有的时候接收到的是email 地址。
如果试图索引一个错误的类型将会报错并且拒绝整个文档,ignore_malformed可以无视不规则数据。如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引。
建立索引
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"number_one": {
"type": "integer",
"ignore_malformed": true
},
"number_two": {
"type": "integer"
}
}
}
}
}
写入数据
PUT my_index/_doc/1
{
"text": "Some text value",
"number_one": "foo"
}
PUT my_index/_doc/2
{
"text": "Some text value",
"number_two": "foo"
}
上面的例子中number_one接受integer类型,ignore_malformed属性设为true,因此文档一种number_one字段虽然是字符串但依然能写入成功;number_two接受integer类型,默认ignore_malformed属性为false,因此写入失败。
index_options 参数控制将哪些信息添加到倒排索引,用于搜索和突出显示目的。
参数 | 说明 |
---|---|
docs | 索引存储索引词文档数量,可以解决“文档是否包含索引词”的问题 |
freqs | 索引存储索引词文档数量和索引词频率。索引词频率可以是多次出现的索引词得分高于只出现一次的索引词。 |
positions | 索引存储文档数量和索引词频率以及索引词位置。索引词位置剋用 |
offsets | 索引存储文档数量和索引词频率以及索引词位置和索引词开始结束字符偏移量。偏移量可以用来高亮字符。 |
在elasticsearch 6以后Numeric 字段已弃用index_options参数。
分词字符串字段使用 positions 做默认值, 其他字段使用docs做默认值。
索引映射
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"text": {
"type": "text",
"index_options": "offsets"
}
}
}
}
}
存储文档
PUT my_index/_doc/1
{
"text": "Quick brown fox"
}
高亮查询
GET my_index/_search
{
"query": {
"match": {
"text": "brown fox"
}
},
"highlight": {
"fields": {
"text": {}
}
}
}
结果如下:
{
"took": 76,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5753642,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 0.5753642,
"_source": {
"text": "Quick brown fox"
},
"highlight": {
"text": [
"Quick brown fox"
]
}
}
]
}
}
index 属性指定字段是否索引,不索引也就不可搜索,取值可以为true或者false。
fields可以让同一文本有多种不同的索引方式,比如一个String类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
}
PUT my_index/_doc/1
{
"city": "New York"
}
PUT my_index/_doc/2
{
"city": "York"
}
查询数据(city.raw是city的keywork版本)
GET my_index/_search
{
"query": {
"match": {
"city": "york"
}
},
"sort": {
"city.raw": "asc"
},
"aggs": {
"Cities": {
"terms": {
"field": "city.raw"
}
}
}
}
结果如下:
{
"took": 88,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": null,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": null,
"_source": {
"city": "New York"
},
"sort": [
"New York"
]
},
{
"_index": "my_index",
"_type": "_doc",
"_id": "2",
"_score": null,
"_source": {
"city": "York"
},
"sort": [
"York"
]
}
]
},
"aggregations": {
"Cities": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "New York",
"doc_count": 1
},
{
"key": "York",
"doc_count": 1
}
]
}
}
}
由此可见
Norms 存储各种用于在查询时计算查询条件的相关性得分的标准化因子。
虽然norms 在计算相关性得分时非常有用, 但是同样需要消耗大量内存。
norms 的配置应该在字段和 索引的设置上保持一致
PUT my_index/_mapping/_doc
{
"properties": {
"title": {
"type": "text",
"norms": false
}
}
}
null value不能被索引存储和检索。当一个字段被设置null或者空数组,这个字段会被当作null_value字段。
null_value 属性可以用指定的值替换空值,用于索引存储和检索。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"status_code": {
"type": "keyword",
"null_value": "NULL"
}
}
}
}
}
PUT my_index/_doc/1
{
"status_code": null
}
PUT my_index/_doc/2
{
"status_code": []
}
GET my_index/_search
{
"query": {
"term": {
"status_code": "NULL"
}
}
}
为了支持短语查询,需要保存可分词字符串自顿啊中分词的位置。当字符串字段索引多个值,一个“虚拟”缺口会被加载各个值之间来防止短语查询跨值匹配,缺口的大小可以使用position_increment_gap配置,默认100.
PUT my_index/_doc/1
{
"names": [ "John Abraham", "Lincoln Smith"]
}
GET my_index/_search
{
"query": {
"match_phrase": {
"names": {
"query": "Abraham Lincoln"
}
}
}
}
类型映射、对象字段和嵌套类型字段包含的子字段成为属性。这些属性可以是任何的数据类型,包括对象和嵌套类型。 properties 在下面这些情况添加:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"manager": {
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
},
"employees": {
"type": "nested",
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
}
}
}
}
}
PUT my_index/_doc/1
{
"region": "US",
"manager": {
"name": "Alice White",
"age": 30
},
"employees": [
{
"name": "John Smith",
"age": 34
},
{
"name": "Peter Brown",
"age": 26
}
]
}
通常情况下,索引存储时和搜索时应该使用相同的分析器。以确保查询的索引词和倒排索引的索引词有相同的格式。
但是有些时候,在搜索的时候使用不同的分析器是有意义的。丽日使用edge_ngram tokenizer 自动完成时.
默认情况下,查询使用的分析器应该是字段映射中定义的分析器, 但是我们可以通过search_analyzer 重新设置。
PUT my_index
{
"settings": {
"analysis": {
"filter": {
"autocomplete_filter": {
"type": "edge_ngram",
"min_gram": 1,
"max_gram": 20
}
},
"analyzer": {
"autocomplete": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"autocomplete_filter"
]
}
}
}
},
"mappings": {
"_doc": {
"properties": {
"text": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard"
}
}
}
}
}
PUT my_index/_doc/1
{
"text": "Quick Brown Fox"
}
GET my_index/_search
{
"query": {
"match": {
"text": {
"query": "Quick Br",
"operator": "and"
}
}
}
}
Elasticsearch 允许你为每个字段配置得分算法或者相似算法。similarity 提供了一个简单的算法来选择不同于默认BM25的相似算法, 例如 TF/IDF.
Similarities 大多用于 text 型字段, 但是也可以用于其他类型字段。
默认情况下, 字段取值被索引以便于检索, 但是不会被存储,这就意味着字段可以被检索但是无法取到原始值。
通常情况下,这并不会有什么问题,字段的取值被默认存储在 _source 字段中。 如果你只是希望查询单个字段或者一些字段的值而不是整个_source, 你可以通过数据源过滤来实现。
在特定的情况下存储字段的值是有意义的。例如,一个文档具有 a title, a date, and a very large content , 你只是想倒排查询title 和date 而不是从整个_source检索。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"title": {
"type": "text",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "text"
}
}
}
}
}
PUT my_index/_doc/1
{
"title": "Some short title",
"date": "2015-01-01",
"content": "A very long content field..."
}
GET my_index/_search
{
"stored_fields": [ "title", "date" ]
}
结果如下:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 1,
"fields": {
"date": [
"2015-01-01T00:00:00.000Z"
],
"title": [
"Some short title"
]
}
}
]
}
}
Term vectors 包含分析过程产生的索引词信息,包括:
term_vector接收一下参数
参数 | 说明 |
---|---|
no | 不存储term vectors (默认) |
yes | 只存储字段的索引词 |
with_positions | 字段的索引词和位置会被存储 |
with_offsets | 字段的索引词和偏移量会被存储 |
with_positions_offsets | 字段的索引词和位置和偏移量会被存储 |
设置 with_positions_offsets 会使字段索引的大小翻倍。
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"text": {
"type": "text",
"term_vector": "with_positions_offsets"
}
}
}
}
}
PUT my_index/_doc/1
{
"text": "Quick brown fox"
}
GET my_index/_doc/_search
{
"query": {
"match": {
"text": "brown fox"
}
},
"highlight": {
"fields": {
"text": {}
}
}
}
结果如下:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.5753642,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 0.5753642,
"_source": {
"text": "Quick brown fox"
},
"highlight": {
"text": [
"Quick brown fox"
]
}
}
]
}
}