关于 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 协议》,转载必须注明作者和本文链接
quickly3
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!