【问题标题】:ElasticSearch Painless script: Not able to access nested objects using script scoreElasticSearch Painless 脚本:无法使用脚本分数访问嵌套对象
【发布时间】:2022-01-24 22:55:39
【问题描述】:

我想从特定字段中搜索关键字并返回文档。在这些文档之上,我想遍历每个嵌套对象并从所选文档的同一特定字段中再次搜索关键字。

如果存在关键字,则检查: 如果 boolean isCurrent = True,则设置 isCurrent=0 并将此值附加到列表 else if isCurrent = False,取当前日期时间与结束日期时间之差,以月为单位获取值,并将该值附加到列表中。

最后,从每个文档的列表中获取最小值,并根据最小值对文档进行排序。

我可以通过 script_fields 进行自定义登录,并根据最小值对文档进行排序。当我在 script_score 中使用相同的登录名时,它不起作用。当我调试时,我发现使用 params._source 访问嵌套字段时出现问题。

任何帮助将不胜感激。

请使用 script_fields 找到以下弹性搜索查询。在这里,我从 python 脚本传递 current_milliseconds 值。

    query = {
        'query': {
            "nested": {
                "path": "person.experiences",
                "query": {
                    "query_string": {
                        "query": keywords,
                        "fields": ["person.experiences.description"],
                        "default_operator": "AND"
                    }
                }
            }
        },
        "script_fields": {
            "recency": {
                "script": {
                    "lang": "painless",
                    "inline": """
                            def myString = "";
                            def isCurrent = 0;
                            def isFound = false;
                            def index_position = 0;
                            def recency_num = 0;
                            def result = 0;
                            def list = new ArrayList();

                            // for loop starts here
                            for(int i=0; i<params._source.person.experiences.size(); i++){
                            myString = params._source.person.experiences[i].description;

                            // string match starts here
                            if(myString != null && myString != ''){
                            def matcher1 = /electric/.matcher(myString.toLowerCase());
                            def matcher2 = /vehicle/.matcher(myString.toLowerCase());                    
                            //if(wordMatcher.find()){
                            if (matcher1.find() || matcher2.find()){
                            isFound = true;
                            }

                            if (isFound == true){
                            // recency check starts here
                            isCurrent = params._source.person.experiences[i].isCurrent;
                            if(isCurrent == true){
                            isCurrent=0;
                            result+=isCurrent;
                            list.add(isCurrent);
                            } else{
                            ZonedDateTime now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(params['current_datetime']), ZoneId.of('Z'));
                            ZonedDateTime end_date = ZonedDateTime.parse(params._source.person.experiences[i].end);
                            isCurrent = end_date.until(now, ChronoUnit.MONTHS);
                            list.add(isCurrent);
                            result+=isCurrent;
                            recency_num = isCurrent;
                            }
                            }

                            }
                            }
                            def min = list.get(0);
                            for (int i : list){
                            min = min < i ? min : i;
                            }
                            return min;
                            """,
                    "params": {
                        "search_keywords": "Machine Learning",
                        "current_datetime": current_milliseconds
                    }

                }
            }
        }
    }

提前致谢。

【问题讨论】:

    标签: python elasticsearch


    【解决方案1】:

    在您的情况下,有效的script_score 查询看起来像这样:

    GET my-index/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "function_score": {
                "functions": [
                  {
                    "script_score": {
                      "script": {
                        "source": """
                          def myString = "";
                          def isCurrent = 0;
                          def isFound = false;
                          def index_position = 0;
                          def recency_num = 0;
                          def result = 0;
                          def list = new ArrayList();
              
                          def experiences = params._source.person.experiences;
              
                          // for loop starts here
                          for (int i=0; i<experiences.length; i++){
                            def experience = experiences[i];
                            
                            myString = experience.description;
                
                            // string match starts here
                            if(myString != null && myString != '') {
                              def matcher1 = /electric/.matcher(myString.toLowerCase());
                              def matcher2 = /vehicle/.matcher(myString.toLowerCase());                    
                              
                              if (matcher1.find() || matcher2.find()){
                                isFound = true;
                              }
                
                              if (isFound == true){
                                // recency check starts here
                                isCurrent = experience.isCurrent;
                            
                                if (isCurrent == true){
                                  isCurrent=0;
                                  result += isCurrent;
                                  list.add(isCurrent);
                                } else {
                                  def now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(params['current_datetime']), ZoneId.of('Z'));
                                  def end_date = ZonedDateTime.parse(experience.end);
                                  isCurrent = end_date.until(now, ChronoUnit.MONTHS);
                                  list.add(isCurrent);
                                  result += isCurrent;
                                  recency_num = isCurrent;
                                }
                              }
                            }
                          }
                          
                          if (list.length === 0) {
                            return 0;
                          }
                          
                          def min = list.get(0);
                          
                          for (int i : list){
                            min = min < i ? min : i;
                          }
                          
                          return min;
                        """,
                        "params": {
                            "search_keywords": "Machine Learning",
                            "current_datetime": 1643036066000
                        }
                      }
                    }
                  }
                ]
              }
            }
          ]
        }
      }
    }
    

    请注意,大量的正则表达式、迭代和(日期)解析可以显着提高查询分辨率。

    【讨论】:

    • 我在使用上述 script_score 查询时遇到了运行时错误。因此为了调试它,我注释了source 中的所有代码并打印了def experiences = params._source.person.experiences;。给我一个运行时错误。
    • 从一开始,我就遇到了同样的问题,即访问 params._source.person.experiences,有什么线索吗?
    • 您的所有文档都保证包含这些字段吗?如果没有,您可以将此访问器包装在 try/catch 中。那可以解决它。如果可以,请告诉我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 1970-01-01
    • 2023-02-15
    • 2015-05-30
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多