使用脚本在文本字段上进行ElasticSearch精确匹配

dfty9e19  于 2022-10-06  发布在  ElasticSearch
关注(0)|答案(1)|浏览(178)

我正在尝试使用ElasticSearch查询文档进行搜索,这些文档在text字段中有确切的特定值。我知道,对于术语查询,如果它是keyword字段,则是可能的。不幸的是,我不能更改Map。

{
  "my_index": {
    "aliases": {},
    "mappings": {
      "properties": {
        "my_field": {
          "type": "text"
        },
      }
    },
    "settings": {
      "index": {
        "max_ngram_diff": "60",
        "number_of_shards": "8",
        "blocks": {
          "read_only_allow_delete": "false",
          "write": "false"
        },
        "analysis": {...}
      }
    }
  }
}

我尝试了这个term查询,但没有结果:

{
  "size": 10,
  "index": "my_index",
  "body": {
    "query": {
      "bool": {
        "should": [
          {
            "term": {
              "my_field":"MY_VALUE", //not working
            }
          }
        ],
        "must": [],
        "filter": [],
        "minimum_should_match": 1
      }
    }
  }
}

由于似乎不可能找到该值,因此我尝试使用遵循本指南https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-filter-context.html的脚本。因此,我将term更改为match_phrase,并将脚本添加到筛选器:

{
    "size": 10,
    "index": "my_index",
    "body": {
        "query": {
            "bool": {
                "should": [{
                    "match_phrase": {
                        "my_field": {
                            "query": "MY_VALUE",
                            "boost": 1.5,
                            "slop": 0
                        }
                    }
                }],
                "must": [],
                "filter": [{
                    "script": {
                        "script": {
                            "source": "doc['my_field'] == 'MY_VALUE'"
                        }
                    }
                }],
                "minimum_should_match": 1
            }
        }
    }
}

输出结果显示以下错误:

body:
{
  "error": {
    "root_cause": [
      {
        "type": "script_exception",
        "reason": "runtime error",
        "script_stack": [
          "org.opensearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:101)",
          "org.opensearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:53)",
          "doc['my_field'] === 'MY_VALUE'",
          "    ^---- HERE"
        ],
        "script": "doc['my_field'] === 'MY_VALUE'",
        "lang": "painless",
        "position": {
          "offset": 4,
          "start": 0,
          "end": 30
        }
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "my_index",
        "node": "R99vOHeORlKsk9dnCzcMeA",
        "reason": {
          "type": "script_exception",
          "reason": "runtime error",
          "script_stack": [
            "org.opensearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:101)",
            "org.opensearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:53)",
            "doc['my_field'] === 'MY_VALUE'",
            "    ^---- HERE"
          ],
          "script": "doc['my_field'] === 'MY_VALUE'",
          "lang": "painless",
          "position": {
            "offset": 4,
            "start": 0,
            "end": 30
          },
          "caused_by": {
            "type": "illegal_argument_exception",
            "reason": "No field found for [my_field] in mapping with types []"
          }
        }
      }
    ]
  },
  "status": 400
}

我在网上看到doc似乎不包含text字段(term查询同样的问题)。因此,在阅读了其他一些链接后,我尝试了params._source

"source": "params._source.my_field === 'MY_VALUE'",但出现此错误:

"script": "params._source.my_field === 'MY_VALUE'",
          "lang": "painless",
          "position": {
            "offset": 14,
            "start": 0,
            "end": 38
          },
          "caused_by": {
            "type": "null_pointer_exception",
            "reason": null
          }

哪个是最好的解决方案?同样没有剧本..。

vzgqcmou

vzgqcmou1#

您可能会发现this similar question中的答案很有用。

我最近也开始使用ElasticSearch/OpenSearch,得到了和你一样的问题。我的解决方案是,您可以在当前Map中添加一个子字段,也可以将其称为多字段,如ElasticSearch doc中所述

然而,我发现结果仍然像模糊搜索一样显示分数,但它只包含完全匹配的记录。

对于您的示例,您可以将Map更改为以下内容:

{
    "my_index": {
      "aliases": {},
      "mappings": {
        "properties": {
          "my_field": {
            "type": "text",
            "fields": {
                "raw": { 
                  "type":  "keyword"
                }
            }
          },
        }
      },
    }
}

而您查询的精确匹配将是:

{
  "size": 10,
  "index": "my_index",
  "body": {
    "query": {
      "bool": {
        "should": [
          {
            "term": {
              "my_field.raw":"MY_VALUE", // here
            }
          }
        ],
        "must": [],
        "filter": [],
        "minimum_should_match": 1
      }
    }
  }
}

相关问题