ElasticSearch的query_string无法解析一些字符的查询

8
我正在使用ElasticSearch(2.4)和官方Python客户端进行简单查询。我的代码如下:
from elasticsearch import Elasticsearch

es_client = Elasticsearch("localhost:9200")
index = "indexName"
doc_type = "docType"

def search(query, search_size):
    body = {
        "fields": ["title"],
        "size": search_size,
        "query": {
            "query_string": {
                "fields": ["file.content"],
                "query": query
            }
        }
    }
    response = es_client.search(index=index, doc_type=doc_type, body=body)
    return response["hits"]["hits"]

search("python", 10) # Works fine.

问题出现在我的查询中包含不平衡的括号或方括号时。例如,使用search("python {programming", 10),ES会抛出:

elasticsearch.exceptions.RequestError: TransportError(400, u'search_phase_execution_exception', u'Failed to parse query [python {programming}]')

这是ES预期的行为吗?它不使用分词器来删除所有这些字符吗?

注意:我在使用Java时也遇到了这个问题。

5个回答

11

虽然我晚了,但我在这里发帖,希望能帮助其他人。正如我们从 Elasticsearch 文档 这里 所知,ES 有一些保留字符。

这些保留字符是:+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /

所以,现在您有两种可能的解决方案来解决它。当我遇到特殊字符问题时,这些解决方案对我完美运作:

解决方案1:使用\\包装您的特殊字符。

"query": {
    "bool": {
      "must": [
        {
          "match": {
            "country_code.keyword": "IT"
          }
        },
        {
          "query_string": {
            "default_field": "display",
            "query": "Magomadas \\(OR\\), Italy"
          }
        }
      ]
    }
  }

解决方案2:使用 simple_query_string,在您的query上不做任何更改,但它不支持default_field,因此您可以使用fields代替。

  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "country_code.keyword": "IT"
          }
        },
        {
          "simple_query_string": {
            "fields": ["display"], 
            "query": "Magomadas (OR), Italy"
          }
        }
      ]
    }
  }

9

6

如前所述,一些字符需要进行转义

+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /

"query": "my:name*&&" 应该改为 "query": "my\\:name\\*\\&&"


正则表达式拯救您 ✨

通过简单的正则表达式,我们可以轻松转义这些字符

Python

import re

def escape_elasticsearch_query(query):
    return re.sub('(\+|\-|\=|&&|\|\||\>|\<|\!|\(|\)|\{|\}|\[|\]|\^|"|~|\*|\?|\:|\\|\/)', '\\\\\\1', query)


query = 'my:name*&&'
escaped_query = escape_elasticsearch_query(query)
print(escaped_query)

输出:

my\:name\*\&&

Javascript

function escapeElasticsearchQuery(query) {
    return query.replace(/(\+|\-|\=|&&|\|\||\>|\<|\!|\(|\)|\{|\}|\[|\]|\^|"|~|\*|\?|\:|\\|\/)/g, '\\$&');
}


let query = 'my:name*&&';
let escapedQuery = escapeElasticsearchQuery(query);
console.log(escapedQuery);

输出:

my\:name\*\&&

感谢提供正则表达式。不过我认为发现了一个小问题,需要添加一个额外的反斜杠来正确转义反斜杠(只在Python中进行了此操作): re.sub('(\+|\-|\=|&&|\|\||\>|\<|\!|\(|\)|\{|\}|\[|\]|\^|"|~|\*|\?|\:|\\\|\/)', '\\\\\\1', query) - Mike A.

2

在ES中使用query_string有点奇怪。您需要用双反斜杠进行转义。

以下会失败:

GET index1/job/_search
{
  "query": {
    "query_string": {
      "fields": ["jobNumber"],
      "query": "827950 { foo"
    }
  }
}

以下内容有效
GET index1/job/_search
{
  "query": {
    "query_string": {
      "fields": ["jobNumber"],
      "query": "827950 \\{ foo"
    }
  }
}

注意:如果您正在使用术语查询或类似的内容,则无需转义该 {

0
关于当前的Elasticsearch版本(8.10),有一个未记录的标志“escape”,它可以为您转义查询字符串(https://github.com/elastic/elasticsearch/issues/77604)。
因此,您可以编写此类请求而无需自行转义特殊符号:
{
  "query": {
    "bool": {
      "must": {
        "query_string": {
          "escape": true,
          "query": "elf bar/eb design",
        }
      }
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接