【问题标题】:In Elasticsearch, how to use a range query on a text field?在 Elasticsearch 中,如何在文本字段上使用范围查询?
【发布时间】:2023-02-16 18:51:47
【问题描述】:

Elasticsearch 索引中有一个“备注”字段,其中包含各种备注以及给出该备注的日期。例如:

remark
------
14/02/2023 To be updated ; 15/02/2023 Further action is needed ; 16/02/2023 Looks good

由于某些特定于实施的原因,我无法将日期拆分为一个单独的字段。我需要在“备注”字段中查询与给定日期范围匹配的所有记录。例如:检索日期范围为 15/02/2023 和 16/02/2023 的所有记录。

我在 Elasticsearch 中编写了以下查询:

GET myindex/_search
{
"query"
  : {
    "bool"
    : {
        "must"
        : [
            {
                "range"
                : {
                    "remark"
                    : {
                        "gte" : "2023-02-15",
                        "lte" : "2023-02-16"
                    }
                }
            }
        ]
    }
  },
  "highlight"
  : {
    "fields"
    : {
        "content"
        : {
            "type"                : "unified",
            "fragment_size"       : 150,
            "number_of_fragments" : 3,
            "pre_tags"            : [""],
            "post_tags"           : [""]
        }
    }
  },
  "size"
  : 1000
}

上面的查询不起作用,因为字段“remark”不是日期时间类型。这个问题有什么解决方法吗?

【问题讨论】:

  • 您能否在事后更新文档以便将这些日期添加到您可以查询的另一个字段中?
  • 不,不允许,不允许更改结构。

标签: elasticsearch dsl querydsl


【解决方案1】:

是的,可以使用文本或者关键词range 查询的字段类型,但这是一个昂贵的查询,因此默认情况下禁用它。

使用带有文本和关键字字段的范围查询

如果出现以下情况,将不会执行文本或关键字字段的范围查询 search.allow_expensive_queries 设置为 false。

我不建议您启用它,但如果您愿意,可以使用:

PUT _cluster/settings
{
  "transient": {
    "search.allow_expensive_queries": "true"
  }
}

推荐: 添加一个新字段:

PUT index_name/_mapping
{
  "properties": {
    "remark_date": {
      "type": "date"
    }
  }
}

并更新数据,通过查询更新将为每个文档添加一个新的字段和值。

POST index_name/_update_by_query?wait_for_completion=false

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#ranges-on-text-and-keyword

【讨论】:

    【解决方案2】:

    有一种解决方案可以使用 regex 内部查询来检查日期。

    您可以尝试这个版本的查询并给出它是否有效的评论。

    例子:

    GET myindex/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "script": {
                "script": {
                  "source": "def remark = doc['remark'].value; def pattern = /\d{2}\/\d{2}\/\d{4}/; def matcher = pattern.matcher(remark); if (matcher.find()) { def remarkDate = matcher.group(); return remarkDate >= '15/02/2023' && remarkDate <= '16/02/2023'; } else { return false; }",
                  "lang": "painless"
                }
              }
            }
          ]
        }
      },
      "highlight": {
        "fields": {
          "remark": {
            "type": "unified",
            "fragment_size": 150,
            "number_of_fragments": 3,
            "pre_tags": [""],
            "post_tags": [""]
          }
        }
      },
      "size": 1000
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 2022-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多