关于 Elasticsearch nested field /script 的一些复杂查询
关于 Elasticsearch nested field /script 的一些复杂查询
1.拟相似度百分比评分
nested filed 模拟相似度按照相似度百分比,给予不同评分
关键:重复打分机制
minimum_should_match 为输入文本分词总数的最小匹配百分比,比如当你输入的查询文本的”you are here for whole day”该文本有6个分词,同时设置minimum_should_match 为50%,即6*50% = 3 这个查询就只会返回至少有3个分词匹配的文档
例子:experiences.workSoldDesc 字段相似度为50% socre 为原始socre,达到70%,socre 为两倍
GET 1_Talents/_search
{
"query": {
"bool": {
"should": [
{
"nested": {
"path": ["experiences"],
"query": {
"query_string": {
"default_field": "experiences.workSoldDesc",
"query": "Saas Information",
"minimum_should_match": "50%"
}
}
}
},
{
"nested": {
"path": ["experiences"],
"query": {
"query_string": {
"default_field": "experiences.workSoldDesc",
"query": "Saas Information",
"minimum_should_match": "70%"
}
}
}
}
]
}
},
"_source": [
"experiences.roles.id",
"experiences.workSoldDesc",
"experiences.industries.id"
]
}
2.histogram查询
histogram:
POST /1_Talents/_search
{
"query": {
"nested": {
"path": "experiences",
"query": {
"query_string": {
"query": "experiences.talentId:*"
}
}
}
},
"size": 0,
"_source":["experiences.talentId"],
"aggs" : {
"nesting" : {
"nested": {
"path": "experiences"
},
"aggs": {
"cate":{
"histogram": {
"field" : "experiences.talentId",
"interval" : 10
}
}
}
}
}
}
3.terms聚合查询:
注意:
返回查询结果中的doc_count 并不是一般的doc总数,而是一个doc 的nested 字段的匹配次数之和,即doc数会因为nested字段的原因被重复统计。
建议:使用copy_to属性将nested字段的中的属性,自动复制到一个非nested字段中,或者由代码处理
POST /1_Talents/_search?size=0
{
"aggs" : {
"nesting" : {
"nested": {
"path": "experiences"
},
"aggs": {
"cate":{
"terms": {
"field" : "experiences.talentId"
}
}
}
}
}
}
4.script fileds (使用nested类型字段,格式化并求和,计算工作时长 )
painless 是将java 一些对象和函数封装成painless api 。
例子:
根据experince 的startAt/endAt 计算每个exp的工作时长,当不存在endAt 时候,默认endAt 为now
GET /1_Talents/_search
{
"query" : {
"nested": {
"path": "experiences",
"query": {
"query_string": {
"fields": ["experiences"],
"query": "experiences:* && -experiences.endAt:*"
}
}
}
},
"script_fields": {
"exp_work_length": {
"script": {
"lang": "painless",
"source": """
def resp = [];
for(exp in params._source.experiences){
def item = ['exp_id':exp.id];
if(exp.startAt != null){
item['startAt'] = exp.startAt;
item['title'] = exp.title;
ZonedDateTime zdt1 = ZonedDateTime.parse(exp.startAt);
ZonedDateTime zdt2;
if(exp.endAt != null){
zdt2 = ZonedDateTime.parse(exp.endAt);
item['current'] = false;
}else{
def now_ts = new Date().getTime();
def now_inst = Instant.ofEpochMilli(now_ts);
zdt2 = ZonedDateTime.ofInstant(now_inst,ZoneId.of('Z'));
item['current'] = true;
}
def diff = ChronoUnit.MONTHS.between(zdt1, zdt2);
item['endAt'] = exp.endAt;
item['wrok_len_of_months'] = diff;
resp.add(item);
}
}
return resp
"""
}
}
}
}
5.script aggragation 的子聚合查询(包含nested的字段)
注意:
agg script 主要工作原理是通过获得兄弟agg 结果来进行编程。
agg script 拿不到doc字段,因此无法根据doc来计算
子agg script拿不到父亲agg 兄弟的agg结果
agg 不能使用script_fileds 进行计算。(https://discuss.elastic.co/t/can-elasticsearch-do-group-by-and-order-by-count/65365/2)
所以需要先计算再进行统计的字段,不能在script中实现,建议还是先由程序计算后,直接存储到indx里面。
例子:
下面的例子是通过expereices 中的talentId ,来计算文档分布情况,同时想要获得不同 talentId 分布下experience.id的id求和,可以用于实验上述注意项。
POST /1_Talents/_search
{
"query": {
"nested": {
"path": "experiences",
"query": {
"query_string": {
"query": "experiences.talentId:*"
}
}
}
},
"size": 0,
"_source":["experiences.talentId"],
"aggs" : {
"nesting" : {
"nested": {
"path": "experiences"
},
"aggs": {
"cate":{
"histogram": {
"field" : "experiences.talentId",
"interval" : 10
},
"aggs": {
"total_id":{
"sum": {
"field": "experiences.id"
}
},
"script_aggs": {
"bucket_script": {
"buckets_path": {
"total_id":"total_id"
},
"script": "params.total_id"
}
}
}
}
}
},
"p_id":{
"sum": {
"field": "id"
}
}
}
}
6.script query
下面的script查询模拟一般查询的experiences.startAt:*
注意script query 无法使用params[‘_source’]
POST /1_Talents/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "experiences",
"query": {
"script": {
"script": """
return doc['experiences.startAt'].size()>0
"""
}
}
}
}
]
}
}
}
7.function score => scirpt score
根据不同条件和doc 值返回不同的score 权重乘数
无法得到该文档条目1的效果,因为function score 中拿不到字段的匹配百分比和匹配次数
GET 1_Talents/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"should": [
{
"nested": {
"path": ["experiences"],
"query": {
"query_string": {
"default_field": "experiences.workSoldDesc",
"query": "Saas Information",
"minimum_should_match": "50%"
}
}
}
},
{
"nested": {
"path": ["experiences"],
"query": {
"query_string": {
"default_field": "experiences.workSoldDesc",
"query": "Saas Information",
"minimum_should_match": "70%"
}
}
}
}
]
}
},
"functions":[
{
"filter": { "match": { "id": 76 } },
"random_score": {},
"weight": 10
},
{
"filter": { "match": { "id": "91" } },
"weight": 100
},
{
"script_score": {
"script": "if(doc['id'].value == 109){return 1000}"
}
}
]
}
},
"_source": ["_score"],
"explain": false
}
8.painless 上下文
painless 的编程环境,有很多内存变量和获取数据的API,但是在不同的功能里面,这个能用的api都是不一样的。
例如:
首先params._source, doc , ctx 概念上属于painless context(painless上下文,三者都是用于Script 编程中获取doc field 用的,
但是不是所有情况都有这三个对象
详情可以查阅 painless 上下文列表:
script query 使用的是filter context
www.elastic.co/guide/en/elasticsea...
本作品采用《CC 协议》,转载必须注明作者和本文链接