前言

本文基于elasticsearch7.3.0版本

映射是定义文档及其包含的字段如何存储和索引的过程
在这里插入图片描述

查看索引mappings

GET index_test/_mapping

元字段meta-fields

元字段用于自定义如何处理与文档相关的元数据,主要包括_source,_index,_type,_id

_source

_source字段存储了在索引时传递的原始JSON文档
_source字段本身没有被索引(因此不是可搜索的),但它被存储起来,以便在执行时可以返回

#  创建索引
PUT index_test
{
  "mappings": {
    "_source": {
      // true,默认值,表示使用_source field
      // false,表示禁用,禁用_source field将导致查询时不会返回索引时的原始JSON文档
      // 设置成false时注意:虽然字段不存储在_source field中,但是我们仍然可以搜索这个字段
      "enabled": true, 
      // 指定哪些字段保存在_sorce field里面
      // 当includes不存在或者存在时数组大小为空,此时存储的字段就是去除excludes之外的字段
      // 当includes存在且数组大小不为空,此时存储的字段就是includes指定的字段
      "includes": ["field1"],
      // 指定哪些字段不保存在_source field里面
      "excludes": ["field3"]
    },
    "properties": {
      "field1": {
        "type": "keyword"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "keyword"
      }
    }
  }
}

	// includes不存在,excludes中的字段排除掉,所以保存:field1,field2
    "_source": {
      "excludes": ["field3"]
    }

	// includes存在但是数组为空,excludes中的字段排除掉,所以保存:field1,field2
	"_source": {
      "includes": [],
      "excludes": ["field3"]
    }

	// includes存在且数组不为空,保存的字段就是includes指定的字段,所以保存:field1
	"_source": {
      "includes": ["field1"],
      "excludes": ["field3"]
    }

_index

表示文档存储在哪个索引中,也可以用来查询和聚合使用

# 聚合每个索引中的文档数
GET _search
{
  "size": 0, 
  "aggs": {
    "index_terms_aggs": {
      "terms": {
        "field": "_index"
      }
    }
  }
}

_type

表示文档存储在索引中的哪个类型里,只有一个类型_doc

_id

文档唯一标识

字段类型

核心数据类型

字符串

  • text:索引时会分词,类比查询中的match,查询时会分词
  • keyword:索引时不会分词,原样索引,类比查询中的term,查询时不会分词
# 创建索引
PUT index_test
{
  "mappings": {
    "properties": {
      "content":{
      	// text, 索引时会分词, 可以设置analyzer
        "type": "text"
      },
      "tag":{
      	// keyword, 索引时不会分词, 不能指定analyzer, 否则创建索引时会报错
        "type": "keyword"
      }
    }
  }
}

# 会分词,这里mappings中没有指定analyzer,也没有指定default分析器,所以使用内置standard分析器
POST index_test/_analyze
{
  "text":["这是测试文本,测试分词效果"],
  "field": "content"
}

# 不会分词
POST index_test/_analyze
{
  "text":["这是测试文本,测试分词效果"],
  "field": "tag"
}

注意:keyword类型不能设置analyzer,否则创建索引时会报错

# keyword类型指定分析器报错
PUT index_test
{
  "mappings": {
    "properties": {
      "content":{
        "type": "text"
      },
      "tag":{
        "type": "keyword",
        "analyzer": "ik_max_word"
      }
    }
  }
}

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Mapping definition for [tag] has unsupported parameters:  [analyzer : ik_max_word]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [_doc]: Mapping definition for [tag] has unsupported parameters:  [analyzer : ik_max_word]",
    "caused_by": {
      "type": "mapper_parsing_exception",
      "reason": "Mapping definition for [tag] has unsupported parameters:  [analyzer : ik_max_word]"
    }
  },
  "status": 400
}

默认创建的mappings, 每个字符串字段解析成text, 并且会默认一个fields为keyword

// my_test索引事先不存在
POST my_test/_doc/1
{
  "userName": "jack",
  "password": "123456"
}

// 查看mappings
GET my_test/_mapping

// 结果
{
  "my_test" : {
    "mappings" : {
      "properties" : {
        "password" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "userName" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

数字

整数类型
类型取值范围描述
byte-128 ~ 127(-27 ~ 27-1)1个字节,一个有符号的8 bit整数
short-32768 ~ 32767(-215 ~ 215-1)2个字节,一个有符号的16 bit整数
integer-231 ~ 231-14个字节,一个有符号的32 bit整数
long-263 ~ 263-18个字节,一个有符号的64 bit整数

如何选择类型
就整数类型而言(byte, short, integer和long),应该选择适合用例的最小类型。这将有助于索引和搜索效率更高。但是,请注意,存储是基于存储的实际值进行优化的,因此选择一种类型而不是另一种类型将不会对存储需求产生影响。
比如:明确一个值最小值为0,最大为100,选择byte

浮点类型
类型取值范围
double64 bit双精度IEEE 754浮点数
float32 bit单精度IEEE 754浮点数
half_float16 bit半精度IEEE 754浮点数
scaled_float缩放类型的的浮点数,由一个double和一个long型缩放因子组成

如何选择类型
对于浮点类型,优先考虑使用带缩放因子的scaled_float浮点类型
如果scaled_float不是很合适,那么你应该在浮点类型中选择适合用例的最小类型:double, float和half_float

对于double、float和half_float,-0.0和+0.0是不同的值,使用term查询查找-0.0不会匹配+0.0,同样range查询中上边界是-0.0不会匹配+0.0,下边界是+0.0不会匹配-0.0。

scaled_float说明:比如价格需要保留三位小数,price为132.889,缩放因子为1000,存起来就是132889

PUT my_test
{
  "mappings": {
    "properties": {
      "price":{
        "type": "scaled_float",
        // 设置缩放因子,这个参数必须有,否则创建索引时报错
        "scaling_factor": 1000
      }
    }
  }
}

PUT my_test/_doc/1
{
  // 实际存储的值 : 132.889 * 1000(缩放因子) = 132889
  "price": 132.889
}

日期

ElasticSearch 内部会将日期数据转换为UTC,并存储为milliseconds-since-the-epoch的long型整数(时间戳)
详细请参考这篇博客:Elasticsearch-日期数据类型和时区详解

布尔

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

布尔
true, “true”
false, “false”

二进制

这个binary类型接受base 64编码的字符串,可用来存储二进制形式的数据
默认情况下,字段只存储不索引,因此也不能被搜索
注意: base 64编码的二进制值必须没有嵌入的换行符。\n

范围

类型取值
integer_range带符号的32 bit整数的范围,-231 ~ 231-1
long_range有符号64 bit整数的范围,-263 ~ 263-1
float_range32 bit单精度IEEE 754浮点数范围
double_range64 bit双精度IEEE 754浮点数范围
date_range表示milliseconds-since-the-epoch的long型整数, 即64 bit整数毫秒的无符号日期值的范围
ip_range支持以下任一项的IP值范围IPv 4或IPv 6(或混合)地址
PUT range_index
{
  "mappings": {
    "properties": {
      "expected_attendees": {
        "type": "integer_range"
      },
      "time_frame": {
        "type": "date_range", 
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

PUT range_index/_doc/1?refresh
{
  "expected_attendees" : { 
    "gte" : 10,
    "lte" : 20
  },
  "time_frame" : { 
    "gte" : "2015-10-31 12:00:00", 
    "lte" : "2015-11-01"
  }
}

复合数据类型

数组

在Elasticearch中,没有专门的array数据类型。默认情况下,任何字段都可以包含零或多个值,但是数组中的所有值必须具有相同的数据类型,ElasticSearch不支持元素为多个数据类型:[ 10, “some string” ]
数组可能包含null值,这些值要么为配置的null_value或者完全跳过。空数组[]被视为缺失字段–一个没有值的字段
常见数组:

  • 字符串数组:[“one”, “two” ]
  • 整数数组:[1, 2 ]
  • 嵌套数组:[1, [ 2, 3]这相当于[1, 2, 3 ]
  • 对象数组:[{ “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }]

注意:对象数组不像预期的那样工作:不能独立于数组中的其他对象查询每个对象。如果您需要能够做到这一点,那么您应该使用nested数据类型,而不是object数据类型。

对象

JSON文档本质上是分层的:文档可能包含内部对象,而内部对象也可能包含内部对象本身
不需要显示的设置字段type为object, 因为这是默认值

# my_index事先不存在
PUT my_index/_doc/1
{
  "region": "US",
  "manager": {
    "age": 30,
    "name": {
      "first": "John",
      "last": "Smith"
    }
  }
}

# 在内部,这个文档被索引为一个简单的键值对列表,如下所示:
{
  "region":             "US",
  "manager.age":        30,
  "manager.name.first": "John",
  "manager.name.last":  "Smith"
}

# 查看这个索引mappings
GET my_index/_mapping

# 结果
{
  "my_index" : {
    "mappings" : {
      "properties" : {
        "manager" : {
          "properties" : {
            "age" : {
              "type" : "long"
            },
            "name" : {
              "properties" : {
                "first" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                },
                "last" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword",
                      "ignore_above" : 256
                    }
                  }
                }
              }
            }
          }
        },
        "region" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

对象数组

nested数据类型是一种特殊的object数据类型,它允许对对象数组进行索引,使它们可以彼此独立地查询

object数据类型存在的问题

# my_index索引事先不存在, user字段被动态添加为object字段类型
PUT my_index/_doc/1
{
  "group": "fans",
  "user": [
    {
      "first": "John",
      "last": "Smith"
    },
    {
      "first": "Alice",
      "last": "White"
    }
  ]
}

# 内部存储, user.first和user.last之间没有了关联关系
{
  "group" :        "fans",
  "user.first" : [ "alice", "john" ],
  "user.last" :  [ "smith", "white" ]
}

# 查询, 此时不能正确地匹配alice AND smith, 本来应该查询不出来数据的, 这时候查询出来了id为1的文档
GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user.first": "Alice"
          }
        },
        {
          "match": {
            "user.last": "Smith"
          }
        }
      ]
    }
  }
}

如果需要索引对象数组并维护数组中每个对象的独立性,则应使用nested数据类型,而不是object数据类型。在内部,嵌套对象将数组中的每个对象索引为单独的隐藏文档,这意味着每个嵌套对象可以独立于其他对象进行查询,nested查询:

# 创建索引
PUT my_index
{
  "mappings": {
    "properties": {
      "user": {
      	// 设置字段类型
        "type": "nested",
        "properties": {
			"first": {
				"type": "keyword"
			},
			"last": {
				"type": "keyword"
			}
		}
      }
    }
  }
}

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

# 使用nested查询
GET my_index/_search
{
  "query": {
    "nested": {
      "path": "user",
      "query": {
        "bool": {
          // 此查询匹配,因为Alice和White在同一个嵌套对象中
          "must": [
            {
              "match": {
                "user.first": "Alice"
              }
            },
            {
              "match": {
                "user.last": "White"
              }
            }
          ]
        }
      },
      // inner_hits允许我们高亮显示匹配的嵌套文档
      "inner_hits": {
        "highlight": {
          "fields": {
            "user.first": {}
          }
        }
      }
    }
  }
}

地理数据类型

地点

类型字段geo_point接受经纬度对

  • lat:纬度
  • lon:经度

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

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

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

# geo_point表示为字符串, 格式为: "lat,lon"(纬度,经度)
PUT my_index/_doc/2
{
  "text": "Geo-point as a string",
  "location": "41.12,-71.34" 
}

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

# 数组表示的geo_point, 格式为: [lon, lat]([经度, 纬度])
PUT my_index/_doc/4
{
  "text": "Geo-point as an array",
  "location": [ -71.34, 41.12 ] 
}

# POINT字符串, 存储时报错
# {
# 	"type": "parse_exception",
# 	"reason": "unsupported symbol [o] in geohash [POINT(-71.34 41.12)]"
# }
PUT my_index/_doc/5
{
  "text": "Geo-point as a WKT POINT primitive",
  "location" : "POINT (-71.34 41.12)" 
}

# 查询
GET my_index/_search
{
  "query": {
    "geo_bounding_box": { 
      "location": {
        "top_left": {
          "lat": 42,
          "lon": -72
        },
        "bottom_right": {
          "lat": 40,
          "lon": -74
        }
      }
    }
  }
}

地形

这个geo_shape数据类型为任意几何形状(如矩形和多边形)的索引和搜索提供了便利。当要索引的数据或正在执行的查询包含的形状不只是点时,就应该使用它。

可以对类型使用地质形状查询.

特殊数据类型

ip

ip字段可以索引/存储IPv 4或IPv 6地址

completion

这个completion suggester(建议)提供自动完成/搜索即用类型的功能。这是一个导航功能,引导用户在输入时获得相关结果,从而提高搜索精度。它不是用于拼写更正,也不是指像term或phrase suggester。

理想情况下,自动完成功能应该和用户输入一样快,以提供与用户已经输入的内容相关的即时反馈。因此,completion suggester是优化的速度。该建议程序使用的数据结构支持快速查找,但构建成本很高,并且存储在内存中。

token_count

token_count类型是一个integer类型,该字段接受字符串值,对它们进行分析,然后对字符串中的标记数进行索引。

PUT my_index
{
  "mappings": {
    "properties": {
      "name": { 
      	// 使用内置的standard分析器
        "type": "text",
        "fields": {
          "length": { 
            "type":     "token_count",
            "analyzer": "standard"
          }
        }
      }
    }
  }
}

# name分析后有2个token
PUT my_index/_doc/1
{ "name": "John Smith" }

# name分析后有3个token
PUT my_index/_doc/2
{ "name": "Rachel Alice Williams" }

# 查询name包含3个token的文档
GET my_index/_search
{
  "query": {
    "term": {
      "name.length": 3 
    }
  }
}

映射参数

analyzer和search_analyzer

详细参考:Elasticsearch-分析器详解

  • analyzer: 指定字段索引和查询时的分析器
  • search_analyzer: 指定字段查询时的分析器, 优先级高于analyzer

字段索引时分析器优先级:

  1. mappings analyzer
  2. settings default分析器
  3. 内置standard分析器

字段查询时分析器优先级

  1. 查询时指定的分析器
  2. mappings search_analyzer
  3. mappings analyzer
  4. settings default_search分析器
  5. settings default分析器
  6. 内置standard分析器

format

自定义日期格式化格式

index

index选项控制字段值是否被索引,elasticsearch默认索引所有字段,它接受true或false, 默认为true
没有被索引的字段不可查询, 但是仍然会存储在_source中

enabled

ElasticSearch试图索引给它的所有字段,但有时你只想存储字段而不对其进行索引

这个enabled设置,该设置只能应用于顶层映射定义和object字段,导致Elasticearch完全跳过对字段内容的解析。仍然可以从_source字段,但它不能搜索,也不能存储在store字段中

PUT my_index
{
  "mappings": {
    "properties": {
      "session_data": { 
        "type": "object",
        // 这个session_data字段被禁用
        "enabled": false,
        // 这个时候store只能为false, 为true则创建索引时报错
        "store": false
      }
    }
  }
}

# enabled为false, store为true, 创建索引报错
{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Mapping definition for [session_data] has unsupported parameters:  [store : true]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [_doc]: Mapping definition for [session_data] has unsupported parameters:  [store : true]",
    "caused_by": {
      "type": "mapper_parsing_exception",
      "reason": "Mapping definition for [session_data] has unsupported parameters:  [store : true]"
    }
  },
  "status": 400
}

# 任意数据都可以传递给session_data字段,因为它将被完全忽略
PUT my_index/_doc/session_1
{
  "session_data": { 
    "arbitrary_object": {
      "some_array": [ "foo", "bar", { "baz": 2 } ]
    }
  }
}

# 注意,由于Elasticsearch完全跳过解析字段内容,所以可以将非对象数据添加到禁用的字段中
# 这个session_data也将忽略不是JSON对象的值
PUT my_index/_doc/session_2
{
  "session_data": "none"
}

整个映射也可能被禁用,在这种情况下,文档存储在_source字段,这意味着可以检索该字段,但没有以任何方式对其内容进行索引

PUT my_index
{
  "mappings": {
  	// 整个映射被禁用
    "enabled": false 
  }
}

PUT my_index/_doc/session_1
{
  "user_id": "kimchy",
  "session_data": {
    "arbitrary_object": {
      "some_array": [ "foo", "bar", { "baz": 2 } ]
    }
  },
  "last_updated": "2015-12-06T18:20:22"
}

# 可以检索文档
GET my_index/_doc/session_1 

# 检查映射会发现没有添加任何字段
GET my_index/_mapping 

# 返回
{
  "my_index" : {
    "mappings" : {
      "enabled" : false
    }
  }
}

copy_to

copy_to参数允许你将多个字段的值复制到一组字段中,然后可以将该字段作为单个字段进行查询

PUT my_index
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "last_name": {
        "type": "text",
        "copy_to": "full_name" 
      },
      "full_name": {
        "type": "text",
        "store": true
      }
    }
  }
}

PUT my_index/_doc/1
{
  "first_name": "John",
  "last_name": "Smith"
}

# full_name字段不会出现在_source中
GET my_index/_search
{
  "query": {
    "match": {
      "full_name": { 
        "query": "John Smith",
        "operator": "and"
      }
    }
  }
}

# 返回
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "first_name" : "John",
          "last_name" : "Smith"
        }
      }
    ]
  }
}

# copy的内容会存储在store字段中
GET my_index/_search
{
  "stored_fields": ["full_name"], 
  "query": {
    "match": {
      "full_name": { 
        "query": "John Smith",
        "operator": "and"
      }
    }
  }
}

# 返回
{
  "took" : 815,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "fields" : {
          "full_name" : [
            "John",
            "Smith"
          ]
        }
      }
    ]
  }
}

store

默认情况下,字段值被索引使它们可以被搜索,但它们不是存储,这意味着可以查询字段,但无法检索原始字段值

但通常这不是问题,默认情况下,字段值已经存储在_source里面,所以store默认值为false
如果你只想检索单个字段或几个字段的值,而不是整个_source字段的值。则可以使用source filtering

使用情况一:没有存储在_source中的字段, 可以使用store存储, 比如说:copy_to字段

使用情况二:只想检索指定字段, 通常这个可以使用source filtering代替

store查询和_source查询区别:

  • IO的区别: 查询整个_source字段或者_source部分字段都是一次IO, store查询每个字段一次IO, 也就是查询多少个字段就有多少次IO
  • 返回值的区别: 查询_source原样返回, 为了保持一致性, 存储的字段总是作为数组返回, 因为无法知道原始字段值是单个值、多个值还是空数组
PUT my_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "store": true 
      },
      "content": {
        "type": "text"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "title":   "Some short title",
  "content": "A very long content field..."
}

# 从store中查询
GET my_index/_search
{
  "stored_fields": ["title"] 
}

# 返回
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          // 一个字段一次IO
          // 为了保持一致性,存储的字段总是作为数组返回, 因为无法知道原始字段值是单个值、多个值还是空数组
          // 如果需要原始值,则应从_source获取字段值
          "title" : [
            "Some short title"
          ]
        }
      }
    ]
  }
}

# 从_source中查询
GET my_index/_search
{
    "_source": {
        "includes": ["title"] 
    }
}

# 返回
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
     	// 整个_source字段是一次IO
        "_source" : {
          "title" : "Some short title"
        }
      }
    ]
  }
}

fields

为了不同的目的,以不同的方式对同一个字段进行索引通常是有用的。这就是multi-fields
例如,字符串可以映射为text字段用于全文搜索,并作为keyword用于排序或聚合的字段
注意:多个字段不会更改_source

PUT my_index
{
  "mappings": {
    "properties": {
      "city": {
        "type": "text",
        "fields": {
          "raw": { 
            "type":  "keyword"
          }
        }
      }
    }
  }
}

PUT my_index/_doc/1
{
  "city": "New York"
}

PUT my_index/_doc/2
{
  "city": "York"
}

GET my_index/_search
{
  "query": {
    "match": {
      "city": "york" 
    }
  },
  "sort": {
    "city.raw": "asc" 
  },
  "aggs": {
    "Cities": {
      "terms": {
        "field": "city.raw" 
      }
    }
  }
}

multi-fields多分析器
multi-fields的另一个用例是以不同的方式分析同一个字段,以获得更好的相关性。
例如,我们可以用standard分析器将文本分解成文字,然后再用english分析器词根形式

PUT my_index
{
  "mappings": {
    "properties": {
      "text": { 
        "type": "text",
        "fields": {
          "english": { 
            "type":     "text",
            "analyzer": "english"
          }
        }
      }
    }
  }
}

PUT my_index/_doc/1
{ "text": "quick brown fox" } 

PUT my_index/_doc/2
{ "text": "quick brown foxes" } 

GET my_index/_search
{
  "query": {
    "multi_match": {
      "query": "quick brown foxes",
      "fields": [ 
        "text",
        "text.english"
      ],
      "type": "most_fields" 
    }
  }
}

null_value

null值不能被索引或搜索。当字段设置为null,(空数组[]或数组为null)它被视为该字段没有值

  • null_value参数允许你把null显式替换为指定的值,以便可以对其进行索引和搜索
  • null_value需要与字段有相同的数据类型。例如,long字段不能指定null_value为字符串
  • null_value只影响数据的索引方式,不会修改_source文件
PUT my_index
{
  "mappings": {
    "properties": {
      "status_code": {
        "type":       "keyword",
        // 显式替换为字符串"NULL"
        "null_value": "NULL" 
      }
    }
  }
}

PUT my_index/_doc/1
{
  // 替换
  "status_code": null
}

PUT my_index/_doc/2
{
  // 空数组不包含显式null,所以不会用null_value
  "status_code": [] 
}

# 查询"NULL", 返回文档1, 不返回文档2 
GET my_index/_search
{
  "query": {
    "term": {
      "status_code": "NULL" 
    }
  }
}

doc_values

默认情况下大多数字段都是被索引的,这使得它们可以被搜索。
倒排索引允许查询在唯一排序的term列表中查找搜索词,并从该列表中立即访问包含该term的文档列表。

在脚本中对字段值的排序、聚合和访问需要不同的数据访问模式。
我们不需要查找term和查找文档,而是需要能够查找文档并找到它在某个field中的term。

doc值是在文档索引时构建的磁盘上数据结构,这使得这种数据访问模式成为可能。
它们存储与_source相同的值,但是以一种面向列的方式来进行排序和聚合,效率要高得多。
几乎所有字段类型都支持doc值,除了text和annotated_text字段

默认情况下,所有支持doc值的字段都启用了这些值。
如果你确定不需要对字段进行排序或聚合,或者访问脚本中的字段值,则可以禁用doc值以节省磁盘空间

PUT my_index
{
  "mappings": {
    "properties": {
      "status_code": { 
      	// status_code字段doc_values默认启用
        "type":       "keyword"
      },
      "session_id": { 
        "type":       "keyword",
        // session_id的doc_values禁用,但仍然可以查询, 不能用于排序和聚合
        "doc_values": false
      }
    }
  }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐