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

mcvgt66p  于 2021-06-13  发布在  ElasticSearch
关注(0)|答案(2)|浏览(314)

我想做一个 Range 搜索现在Map到文本的日期字段。问题是这个领域已经有数据了;因此,删除索引并重新创建一个新的索引不是一个好主意 index 绘制要绘制的字段 date . 所以我考虑对字段应用一个自定义函数来 Range 搜索。有可能吗?

vh0rcniy

vh0rcniy1#

当然可以使用脚本查询,但是您的文本字段需要 fielddata: true 放在上面或者是 .keyword 为脚本键入(例如,多字段)以访问字段值。
一旦处理好了,让我们假设您的文本字段 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"
        }
      }
    }
  }
}

这样做的挑战是脚本在每个查询中都会重新初始化(除非它们被存储),因此速度很慢。因此,最好的方法是使用新的日期字段更新Map,然后调用 _reindex 更新所有文档。不需要删除索引。
现在这种方法的问题是,它不会影响任何新的传入文档。在这种情况下,您可以修改摄取过程以同时包含新的日期字段(因此出于遗留原因,您将有两个具有相同值的字段),或者建立摄取管道来为您执行此操作(->不需要摄取过程调整)。下面是这样一个管道的例子,尽管设计的目的略有不同。原理是一样的。

u5rb5r59

u5rb5r592#

选项1:更新文档而不需要删除和重新创建整个索引。
如果为索引启用了存储,则可以创建具有正确数据类型的子字段。例如,如果现有字段名为 dateText 然后您可以如下更新索引Map,并利用updatebyquery重新索引所有文档。

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

更新Map后使用updateby query。

POST myindex/_update_by_query?conflicts=proceed

完成以上操作后,您可以在上使用范围查询 dateText.dateField .
选项2:您可以使用脚本查询来处理文本到日期的转换和应用范围逻辑。

相关问题