ElasticSearch 数组条件筛选?

数据结构如下:

{
    "id":1,
    "change_records" : [
    {
      "change_time" : 1646039270000
    },
    {
      "change_time" : 1653728870000
    },
    {
      "change_time" : 1658999270000
    },
    {
      "change_time" : 1627463270000
    }
  ]
}

请问如何用es查询 有N条chang_time在M年内的文档呢?

mapping:

{
  "mappings": {
    "_doc": {
      "properties": {
        "id": {
          "type": "long"
        },
        "change_records": {
          "properties": {
            "change_time": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}

我尝试了用脚本查询, 但是一直提示字段不存在

GET /test_index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "script": {
            "script": {
              "source": """
                int matches = 0;
                  def changeRecords = doc['change_records'];
                  for(def t : doc['change_records']){
                    if(t.change_time>= params.start && t.change_time <= params.end) {
                      matches ++;
                    }
                }
                return matches >= params.n ;
              """,
              "lang": "painless",
              "params": {
                "start": 0,
                "end": 1658999270000,
                "n": 1
              }
            }
          }
        }
      ]
    }
  }
}
No field found for [change_records] in mapping with types []

直接用exists是有这个字段的

{
  "query":{
    "bool": {
      "filter": [
        {
          "exists": {
            "field": "change_records"
          }
        }
      ]
    }
  }
}

测试数据:
POST /test_index/_doc

{
  "id" : 51670,
  "change_records":
    [
      {
        "change_time":1646039270000
      },
      {
        "change_time":1653728870000
      },
      {
        "change_time":1658999270000
      },
      {
        "change_time":1627463270000
      }
    ]
  
}
阅读 2.2k
1 个回答

不知道你用的什么开发语言,但是最终都是转换为json发起请求,我大概说一下吧,这个你通过自定义score来判断就行,然后呢,查询条件你校验一下score > 0就行;body部分查询结构大概如下:

{
    "query" : {
        "script_score" : {
            "query" : // 这里放你原本的查询条件,直接复制粘贴进来就行
            "script": { // 最重要的是这部分,自定义过滤脚本,具体参见官方文档
                "source" : '这里放自定义评分脚本,为字符串,具体参见下一节代码',
                "params" : { // 外部参数
                    "start":"这里填入你的开始年份", 
                    "end":"这里填入你的结束年份", 
                    "n":"这里填入你要查的数据条数", 
            }
        }
    }
}

source 脚本部分类似于以下:

def matches = 0;
for (t in doc["change_records"]) { // 你数据里的change_records数据
    // 通过 params 获取外部穿参,参见上面的搜索结构
    if(t.change_time >= params.start && t.change_time <= params.end) {
        matches += 1;
    }
}
return matches >= params.n;

另外,更详细的类似于这种情况的参见我的文章,里面对于类似的这种情况解释得很详细:

Elasticsearch 按照标签匹配个数优先排序查询

推荐问题
宣传栏