进行搜索时是否可以将函数应用于字段?

Is it possible to apply a function to a field when making the search?

我想在 日期 字段上进行 Range 搜索,该字段现在映射到 text。问题是该字段中已经有数据;因此,删除索引并重新创建一个新的 index 以将字段映射为 date 并不是一个好主意。所以我考虑将自定义函数应用于该字段以进行 Range 搜索。这可能吗?

当然可以使用脚本查询,但您的文本字段需要 fielddata: true set on it or be of the .keyword type (as a multifield,例如)脚本才能访问字段值。

一旦处理完毕,让我们假设您的文本字段 dateFieldAsText 包含以秒为单位的纪元时间戳,并且您希望使用人类可读的日期范围过滤 gte 和 lte。然后我们可以将所有内容解析为毫秒,然后进行简单比较:

{
  "query": {
    "script": {
      "script": {
        "source": """
          def doc_ts_milli = Integer.parseInt(doc['dateFieldAsText'].value) * 1000L;
          
          def df = new SimpleDateFormat("yyyy/MM/dd");
          def gte_ts = df.parse(params.gte).getTime();
          def lte_ts = df.parse(params.lte).getTime();
          
          return doc_ts_milli >= gte_ts && doc_ts_milli <= lte_ts
        """,
        "params": {
          "gte": "2020/01/01",
          "lte": "2021/01/01"
        }
      }
    }
  }
}

这样做的挑战在于脚本在每个查询中都会重新初始化(除非 they're stored) and are therefore slow. So the best way to go here would be to update the mapping w/ a new date field and then call _reindex to update all docs。不需要删除索引。

现在这种方法的问题是这不会影响任何新的传入文档。在这种情况下,您要么修改您的摄取过程以也包括该新的日期字段(因此您将有两个字段 w/ 出于遗留原因的相同值)或者您建立一个摄取管道来为您执行此操作(-> 没有摄取过程调整需要)。这是 的示例,尽管其设计目的略有不同。原理是一样的。

选项 1: 无需删除并重新创建整个索引即可更新文档。

如果为索引启用了存储,您可以创建一个具有正确数据类型的子字段。例如如果现有字段名称是 dateText 那么您可以按如下方式更新索引映射并利用查询更新来重新索引所有文档。

PUT myindex/_mapping
{
  "properties": {
    "datetext": {
      "type": "text",
      "fields": {
        "dateField": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss"   //<--- change this as per the data
        }
      }
    }
  }
}

更新映射后使用update by query

POST myindex/_update_by_query?conflicts=proceed

完成上述操作后,您可以在 dateText.dateField.

上使用范围查询

选项 2: 您可以使用 script query 来处理文本到日期的转换并应用范围逻辑。