Elasticsearch的Mapping、聚合查询、乐观锁、写入原理、script
Mapping
概念
mapping就是ES数据字段field的type元数据,ES在创建索引的时候,dynamic mapping会自动为不同的数据指定相应mapping,mapping中包含了字段的类型、搜索方式(exact value或者full text)、分词器等
查看Mapping
#查看product类型的mapping
GET /product/_mapping
映射
Elasticsearch 支持如下简单域类型:
- 字符串:
string
- 整数 :
byte
,short
,integer
,long
- 浮点数:
float
,double
- 布尔型:
boolean
- 日期:
date
JSON type | 域 type |
---|---|
布尔型: true 或者 false |
boolean |
整数: 123 |
long |
浮点数: 123.45 |
float |
字符串,有效日期: 2014-09-15 |
date |
字符串: foo bar |
string |
浮点型123.45 基于版本7.12.1 实际测试发现映射的是float类型,官方文档是double类型
price是long类型而不是integer原因:es的mapping_type是由JSON分析器检测数据类型,而Json没有隐式类型转换(integer=>long or float=> double),所以dynamic mapping会选择一个比较宽的数据类型。
搜索方式
exact value 精确匹配
在倒排索引过程中,分词器会将field作为一个整体创建到索引中
确切值“Foo”和“foo”就并不相同。确切值2014 和2014-09-15也不相同
对"2020-01-01"进行精确搜索的时候,必须用关键字2020-01-01才能搜索出来,如果搜关键字01,是搜索不出来的
full text全文检索
分词、近义词同义词、混淆词、大小写、词性、过滤、时态转换等(normaliztion)
类似于sql模糊查询,但是比模糊查询的功能更强大
(1) 对"2020-01-01"进行全文索引时,搜关键字2017或01都是可以搜索出来的
(2) 对"china"进行全文索引时,搜关键字cn,也可以将china搜索出来
(3) 对"likes"进行全文索引时,搜关键字like,也可以将likes搜索出来
(4) 对"Tom"进行全文索引时,搜关键字tom,也可以将Tom搜索出来
(5) 对"like"进行全文索引时,搜关键字love,也可以将like搜索出来
ES的数据类型
核心类型
-
数字类型
long
,integer
,short
,byte
,double
,float
,half_float
,scaled_float
- 在满足需求的情况下,尽可能选择范围小的数据类型。
-
字符串:String
-
keyword:适用于索引结构化的字段,可以用于过滤、排序、聚合。keyword类型的字段只能通过精确值(exact value)搜索到。Id应该用keyword
text:当一个字段是要被全文搜索的,比如Email内容、产品描述,这些字段应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
为啥不会为text创建索引
字段数据会占用大量堆空间,尤其是在加载高基数
text
字段时。字段数据一旦加载到堆中,就在该段的生命周期内保持在那里。同样,加载字段数据是一个昂贵的过程,可能导致用户遇到延迟问题。这就是默认情况下禁用字段数据的原因 -
有时在同一字段中同时具有全文本(text)和关键字(keyword)版本会很有用:一个用于全文本搜索,另一个用于聚合和排序。
-
-
date(时间类型):exact value
-
布尔类型:boolean
-
range(区间类型):integer_range、float_range、long_range、double_range、date_range
复杂类型
- Object:用于单个JSON对象
- Nested:用于JSON对象数组
- 地理位置:
- Geo-point:纬度/经度积分
- Geo-shape:用于多边形等复杂形状
特有类型
-
IP地址:
ip
用于IPv4和IPv6地址 -
Completion:提供自动完成建议
-
Tocken_count:计算字符串中令牌的数量
-
Murmur3:在索引时计算值的哈希并将其存储在索引中
-
Annotated-text:索引包含特殊标记的文本(通常用于标识命名实体)
-
Percolator:接受来自query-dsl的查询
-
Join:为同一索引内的文档定义父/子关系
-
Rank features:记录数字功能以提高查询时的点击率。
-
Dense vector:记录浮点值的密集向量。
-
Sparse vector:记录浮点值的稀疏向量。
-
Search-as-you-type:针对查询优化的文本字段,以实现按需输入的完成
-
Alias:为现有字段定义别名。
-
Flattened:允许将整个JSON对象索引为单个字段。
-
Shape:
shape
对于任意笛卡尔几何。 -
Histogram:
histogram
用于百分位数聚合的预聚合数值。 -
Constant keyword:
keyword
当所有文档都具有相同值时的情况的 专业化。 -
Array(数组):在Elasticsearch中,数组不需要专用的字段数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值都必须具有相同的数据类型。
ES 7新增:
-
Date_nanos:date plus 纳秒
-
Features:
-
Vector:as
手工创建mapping
#创建date类型为text的mapping
PUT /product/_mapping
{
"properties": {
"date": {
"type": "text"
}
}
}
Mapping parameters(映射参数)
index
是否对创建对当前字段创建索引,默认true,如果不创建索引,该字段不会通过索引被搜索到,但是仍然会在source元数据中展示
analyzer
指定分析器(character filter、tokenizer、Token filters)
boost
对当前字段相关度的评分权重,默认1,其影响范围为词根查询(team query),对前缀、范围查询、全文索引(match query)不生效。
注意:不建议在创建索引映射时使用boost属性,而是在查询时通过boost参数指定。其主要原因如下:
1)无法动态修改字段中定义的boost值,除非使用reindex命令重建索引。
2)相反,如果在查询时指定boost值,每一个查询都可以使用不同的boost值,灵活。
3)在索引中指定boost值,boost存储在记录中,从而会降低分数计算的质量。
coerce
是否进行类型“隐式转换”。es最终存储文档的格式是字符串。
例如存在如下字段类型:
"number_one": {
"type": "integer"
}
声明number_one字段的类型为数字类型,那是否允许接收“6”字符串形式的数据呢?因为在JSON中,“6”用来赋给int类型的字段,也是能接受的,默认coerce为true,表示允许这种赋值,但如果coerce设置为false,此时es只能接受不带双引号的数字,如果在coerce=false时,将“6”赋值给number_one时会抛出类型不匹配异常。
可以在创建索引时指定默认的coerce值
PUT /product3
{
"settings": {
"index.mapping.coerce": false
},
"mappings": {
// 省略字段映射定义
}
}
copy_to
copy_to参数允许您创建自定义的_all字段。换句话说,多个字段的值可以复制到一个字段中例如,first_name和last_name字段可以复制到full_name字段如下:
#字段full_name的值来自 first_name + last_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"
}
}
}
}
关于copy_to重点说明:
- 字段的复制是原始值,而不是分词后的词根。
- 复制字段不会包含在_souce字段中,但可以使用复制字段进行查询。
- 同一个字段可以复制到多个字段,写法如下:"copy_to": [ "field_1", "field_2" ]
★doc_values(正排索引)
当需要对一个字段进行排序时,es需要提取匹配结果集中的排序字段值集合,然后进行排序。倒排索引的数据结构对检索来说相当高效,但对排序就不那么擅长了
对排序、聚合非常高效的数据存储格式首推列式存储,在elasticsearch中,doc_values就是一种列式存储结构,默认情况下绝大多数数据类型都是开启的,即在索引时会将字段的值(或分词后的词根序列)加入到倒排索引中,同时也会该字段的值加入doc_values中,所有该类型的索引下该字段的值用一列存储。
如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc值以节省磁盘空间(
不支持text
和annotated_text
关闭)
dynamic
控制是否可以动态添加新字段
- true 新检测到的字段将添加到映射中。(默认)
- false 新检测到的字段将被忽略。这些字段将不会被索引,因此将无法搜索,但仍会出现在_source返回的匹配项中。这些字段不会添加到映射中,必须显式添加新字段。
- strict 如果检测到新字段,则会引发异常并拒绝文档。必须将新字段显式添加到映射中
eager_global_ordinals
用于聚合的字段上,优化聚合性能
Frozen indices
冻结索引几乎没有集群开销(除了将其元数据保留在内存中),并且被阻止进行写操作。请参阅冻结索引和解冻索引。
有些索引使用率很高,会被保存在内存中,有些使用率特别低,宁愿在使用的时候重新创建,在使用完毕后丢弃数据,Frozen indices的数据命中频率小,不适用于高搜索负载,数据不会被保存在内存中,堆空间占用比普通索引少得多,Frozen indices是只读的,请求可能是秒级或者分钟级
#冻结某个索引
POST / my_index / _freeze
#解冻索引
POST / my_index / _unfreeze
eager_global_ordinals不适用于Frozen indices
如果您使用基于时间的索引来存储日志消息或时间序列数据,则较早的索引可能比最近的索引的搜索频率要低得多。较旧的索引也不会收到索引请求。此外,通常情况下,对较旧索引的搜索是为了执行较慢的响应而可以接受的长期分析。
enable
是否创建倒排索引,可以对字段操作,也可以对索引操作,如果不创建索引,让然可以检索并在_source元数据中展示,谨慎使用,该状态无法修改。
PUT my_index{
"mappings": {
"enabled": false
}}
fielddata
大多数字段可以将索引时生产的磁盘doc_values用于此数据访问模式,但是文本(text)字段不支持doc_values。替代的方案,文本(text)字段使用查询时内存中的数据结构,称为fielddata。 当我们首次将该字段用于聚合,排序或在脚本中使用时,将按需构建此数据结构。 它是通过从磁盘读取每个段的整个反向索引,反转术语↔︎文档关系并将结果存储在JVM堆中的内存中来构建的
Fielddata会占用大量堆空间,尤其是在加载大量的文本字段时。 一旦将字段数据加载到堆中,它在该段的生命周期内将一直保留在那里。 同样,加载字段数据是一个昂贵的过程,可能导致用户遇到延迟的情况。 这就是默认情况下禁用字段数据的原因。
fields
因为不同的目的将同一个字段用不同的方式索引。这就相当于实现了 multi-fields。例如,一个 string 类型字段可以被映射成 text 字段作为 full-text 进行搜索,同时也可以作为 keyword 字段用于排序和聚合:
对于相同索引中具有相同名称的字段,fields设置允许有不同的设置。可以使用PUT映射API将新的多字段添加到已存在的字段中。
Multi_fields 不会改变原始的 _source 字段。
#创建mapping
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
}
#city字段用于全文本搜索
# city.raw用于排序与聚合。
GET my_index/_search
{
"query": {
"match": {
"city": "york"
}
},
"sort": {
"city.raw": "asc"
},
"aggs": {
"Cities": {
"terms": {
"field": "city.raw"
}
}
}
}
format
格式化
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
ignore_above
超过长度将被忽略
ignore_malformed
忽略类型错误
PUT my_index{
"mappings": {
"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" } //数据格式不对
index_options
控制将哪些信息添加到反向索引中以进行搜索和突出显示。仅用于text字段
Index_phrases
提升exact_value查询速度,但是要消耗更多磁盘空间
Index_prefixes
前缀搜索
"index_prefixes": {
"min_chars" : 1,
"max_chars" : 10
}
min_chars
前缀最小长度,>0,默认2(包含)
max_chars
前缀最大长度,<20,默认5(包含)
meta
附加元数据
normalizer
normalizer
是 keyword
的一个属性,可以对 keyword
生成的单一 Term
再做进一步的处理,比如 lowercase
,即做小写变换。使用方法和自定义分词器有些类似,需要自定义
# 自定义 normalizer
PUT test_normalizer
{
"settings": {
"analysis": {
"normalizer": {
"lowercase": {
"type": "custom",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"doc": {
"properties": {
"type": {
"type": "keyword"
},
"type_normalizer": {
"type": "keyword",
"normalizer": "lowercase"
}
}
}
}
}
norms
是否禁用评分(在filter和聚合字段上应该禁用)。
null_value
为null值设置默认值
"null_value": "NULL"
position_increment_gap
对于analyzed string字段,都会考虑把词的位置信息,用于支持位置和短语匹配查询(proximity or phrase queries),例如,有一个字符串字段,该字段中存在多个词“fake”,ElasticSearch引擎会在每个值之间增加一个gap,以防止短语匹配或位置匹配查询出现跨越多个词的异常,这个gap的值就是属性position_increment_gap,默认值是100;
proterties
除了mapping还可用于object的属性设置
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": {
"properties": {
"text": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard"
}
}
}}
similarity
为字段设置相关度算法,支持BM25、claassic(TF-IDF)、boolean
store
存储(store)属性指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段的原始值不会存储,这意味着,该字段能够被查询,但是无法获取字段的原始值。默认情况下,该字段的值会被存储到_source字段中,如果想要获取单个或多个字段的值,而不是整个_source字段,可以使用 source filtering 来实现;但是在特定的条件下,只存储一个字段的值是有意义的(make sense),例如,一个article文档包含:title,postdate和content字段,从文档中只获取title和postdate字段,并且使_source 字段包含content字段,必须通过store属性来控制:
"mappings": {
"my_type": {
"properties": {
"title": {
"type": "string",
"store": true
},
"date": {
"type": "date",
"store": true
},
"content": {
"type": "string", "store": false
}
}
}
}
聚合查询
es聚合是将数据汇总为 度量、统计、以及其它分析。主要分为以下三大类
- 桶(bucket)聚合 - 桶的作用,是按照某种方式对数据进行分组,每一组数据在ES中称为一个
桶
- 度量(metrics)聚合 - 分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为
度量
- Pipeline 聚合 - 从已聚合数据中进行聚合查询
常用的一些度量聚合方式
- Avg Aggregation:求平均值
- Max Aggregation:求最大值
- Min Aggregation:求最小值
- Percentiles Aggregation:求百分比
- Stats Aggregation:同时返回avg、max、min、sum、count等
- Sum Aggregation:求和
- Top hits Aggregation:求前几
- Value Count Aggregation:求总数
- Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组
- Histogram Aggregation:根据数值阶梯分组,与日期类似
- Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组
- Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组
例子
导入数据
#创建数据
#在ES中,需要进行聚合、排序、过滤的字段其处理方式比较特殊,因此不能被分词。这里我们将color和make这两个文字类型的字段设置为keyword类型,这个类型不会被分词,将来就可以参与聚合
PUT /cars
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"color":{
"type": "keyword"
},
"make":{
"type": "keyword"
}
}
}
}
#导入数据
# POST /cars/transactions/_bulk 7.0之后es官方不建议指定类型
POST /cars/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "吉利", "sold" : "2020-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "长城", "sold" : "2020-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "比亚迪", "sold" : "2020-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "比亚迪", "sold" : "2020-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "长城", "sold" : "2020-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "长安", "sold" : "2020-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "吉利", "sold" : "2020-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "长安", "sold" : "2020-02-12" }
聚合为桶
汽车的颜色color来划分桶
GET /cars/_search
{
"size": 0,
"aggs": {
"popular_colors": {
"terms": {
"field": "color.keyword"
}
}
}
}
- size: 查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率
- aggs:声明这是一个聚合查询,是aggregations的缩写
- popular_colors:给这次聚合起一个名字,任意
- terms:划分桶的方式,这里是根据词条划分
- field:划分桶的字段
这里field字段使用的是color.keyword是因为text字段在聚合索引中没有进行优化,使用color会报错
#返回数据
{
"took" : 11,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 8,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"popular_colors" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "red",
"doc_count" : 4
},
{
"key" : "blue",
"doc_count" : 2
},
{
"key" : "green",
"doc_count" : 2
}
]
}
}
}
- hits:查询结果为空,因为我们设置了size为0
- aggregations:聚合的结果
- popular_colors:我们定义的聚合名称
- buckets:查找到的桶,每个不同的color字段值都会形成一个桶
- key:这个桶对应的color字段的值
- doc_count:这个桶中的文档数量
桶内度量
求价格平均值的度量
GET /cars/_search
{
"size": 0,
"aggs": {
"popular_color": {
"terms": {
"field": "color.keyword"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
- aggs:我们在上一个aggs(popular_colors)中添加新的aggs。可见
度量
也是一个聚合,度量是在桶内的聚合 - avg_price:聚合的名称
- avg:度量的类型,这里是求平均值
- field:度量运算的字段
桶内嵌套桶
我们想统计每种颜色的汽车中,分别属于哪个制造商,按照make
字段再进行分桶
GET /cars/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color.keyword"
},
"aggs":{
"avg_price": {
"avg": {
"field": "price"
}
},
"maker":{
"terms":{
"field":"make.keyword"
}
}
}
}
}
}
- 原来的color桶和avg计算我们不变
- maker:在嵌套的aggs下新添一个桶,叫做maker
- terms:桶的划分类型依然是词条
- filed:这里根据make字段进行划分
阶梯分桶
#按照price,5000为一档,并且去除掉数据为0的档
GET /cars/_search
{
"size":0,
"aggs":{
"price":{
"histogram": {
"field": "price",
"interval": 5000,
"min_doc_count": 1
}
}
}
}
批量操作
基于mget批量查询以及基于bulk的批量增删改
mget:批量查询
#查询id为15VdonkBKvp3-bOOQqdZ 和3的数据
GET /_mget
{
"docs": [
{
"_index": "cars",
"_id" : "15VdonkBKvp3-bOOQqdZ"
},
{
"_index": "cars",
"_id": 3
}
]
}
#同上
GET /cars/_mget
{
"docs": [
{
"_id" : "15VdonkBKvp3-bOOQqdZ"
},
{
"_id": 3
}
]
}
#同上
GET /product/_mget
{
"ids":["15VdonkBKvp3-bOOQqdZ","3"]
}
bulk:批量增删改 no-query
#这里一个操作一定要放在一行,不能有空格或换行
POST /_bulk
{ "delete": { "_index": "product2", "_id": "1" }}
{ "create": { "_index": "product2", "_id": "2" }}
{ "name": "_bulk create 2" }
{ "create": { "_index": "product2", "_id": "12" }}
{ "name": "_bulk create 12" }
{ "index": { "_index": "product2", "_id": "3" }}
{ "name": "index product2 " }
{ "index": { "_index": "product2", "_id": "13" }}
{ "name": "index product2" }
{ "update": { "_index": "product2", "_id": "4","retry_on_conflict" : "3"} }
{ "doc" : {"test_field2" : "bulk test1"} }
#加?filter_path=items.*.error 只显示失败的
POST /_bulk?filter_path=items.*.error
{ "delete": { "_index": "product2", "_id": "1" }}
{ "create": { "_index": "product2", "_id": "2" }}
{ "name": "_bulk create 2" }
{ "create": { "_index": "product2", "_id": "12" }}
{ "name": "_bulk create 12" }
{ "index": { "_index": "product2", "_id": "3" }}
{ "name": "index product2 " }
{ "index": { "_index": "product2", "_id": "13" }}
{ "name": "index product2" }
{ "update": { "_index": "product2", "_id": "4","retry_on_conflict" : "3"} }
{ "doc" : {"test_field2" : "bulk test1"} }
ES的乐观锁
ES的乐观锁主要通过version字段实现,每一次修改,删除(逻辑删除)都会使version+1
ES Scripts
- Groovy:ES 1.4.X-5.0,因为存在安全漏洞,新版本不支持
- expression:每个文档的开销较低:表达式的作用更多,可以非常快速地执行,甚至比编写
native
脚本还要快,支持javascript语法的子集:单个表达式。缺点:只能访问数字,布尔值,日期和geo_point字段,存储的字段不可用 - mustache:提供模板参数化查询
- java
- Painless: 一种专门用于Elasticsearch的简单,用于内联和存储脚本,类似于Java,也有注释、关键字、类型、变量、函数等,安全的脚本语言。它是Elasticsearch的默认脚本语言,可以安全地用于内联和存储脚本。
Painless语法
#将id为15VdonkBKvp3-bOOQqdZ的数据中price字段-1
POST cars/_update/15VdonkBKvp3-bOOQqdZ
{
"script": "ctx._source.price -=1"
}
#同上
POST cars/_update/15VdonkBKvp3-bOOQqdZ
{
"script": {
"source": "ctx._source.price -=1"
}
}
#获取cars中所有的数据price
GET cars/_search
{
"script_fields": {
"test field": {
"script": {
"lang": "painless",
"source": "doc['price'].value"
}
}
}
}
#打折模版(脚本模版,对所有索引有效)
POST _scripts/calculate-discount
{
"script": {
"lang": "painless",
"source": "doc['price'].value * params.discount"
}
}
#查看模版
GET _scripts/calculate-discount
#删除模版
DELETE _scripts/calculate-discount
#使用模版
GET cars/_search
{
"script_fields": {
"discount_price": {
"script": {
"id":"calculate-discount",
"params": {
"discount": 0.8
}
}
}
}
}
#测试painless函数方法
PUT test_index/_bulk?refresh
{"index":{"_id":1}}
{"ajbh": "12345","ajmc": "立案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三","SF": "男"},{"XM": "李四","SF": "男"},{"XM": "王五","SF": "女"},{"XM": "赵六","SF": "男"}]}
{"index":{"_id":2}}
{"ajbh": "563245","ajmc": "结案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三2","SF": "男"},{"XM": "李四2","SF": "男"},{"XM": "王五2","SF": "女"},{"XM": "赵六2","SF": "女"}]}
{"index":{"_id":3}}
{"ajbh": "12345","ajmc": "立案案件","lasj": "2020/05/21 13:25:23","jsbax_sjjh2_xz_ryjbxx_cleaning": [{"XM": "张三3","SF": "男"},{"XM": "李四3","SF": "男"},{"XM": "王五3","SF": "女"},{"XM": "赵六3","SF": "男"}]}
#获取所有数据中案件中性别为男的人
#此处要将doc['field'].value换成params['_source']['jsbax_sjjh2_xz_ryjbxx_cleaning']
GET /test_index/_search
{
"size": 0,
"aggs": {
"tag_add_group": {
"sum": {
"script": {
"lang": "painless",
"source": """
int total=0;
for(int i=0;i<params['_source']['jsbax_sjjh2_xz_ryjbxx_cleaning'].length;i++)
{
if(params['_source']['jsbax_sjjh2_xz_ryjbxx_cleaning'][i]['SF']=='男')
total+=i;
}
return total;
"""
}
}
}
}
}
doc['field'].value和params['_source'] ['field']的区别
使用doc关键字,将导致该字段的条件被加载到内存(缓存),这将导致更快的执行,但更多的内存消耗。此外,doc[...]符号只允许简单类型(不能返回一个复杂类型(JSON对象或者nested类型)),只有在非分析或单个词条的基础上有意义。但是,doc如果可能,使用仍然是从文档访问值的推荐方式,因为_source每次使用时都必须加载并解析。使用_source非常缓慢