#python #elasticsearch #replace #lucene #escaping
#python #elasticsearch #заменить #lucene #экранирование
Вопрос:
Я использую клиент elasticsearch python для выполнения некоторых запросов к экземпляру elasticsearch, который мы размещаем.
Я заметил, что некоторые символы нужно экранировать. В частности, эти…
- amp;amp; || ! ( ) { } [ ] ^ " ~ * ? :
Есть ли простой способ сделать это помимо того, что я уже имел в виду? Конечно, есть более чистый способ, чем выполнение
term
.replace(" ", " ")
.replace("-", "-")
# ....etc
Я надеялся, что есть вызов API, который я мог бы использовать, но я не могу найти его в документах. Это кажется достаточно распространенной проблемой, которую кто-то должен был решить.
Кто-нибудь знает «правильный» способ сделать это?
РЕДАКТИРОВАТЬ: я все еще не уверен, есть ли вызов API, но я получил достаточно краткие сведения, чтобы быть довольным.
def needs_escaping(character):
escape_chars = {
'\' : True, ' ' : True, '-' : True, '!' : True,
'(' : True, ')' : True, ':' : True, '^' : True,
'[' : True, ']': True, '"' : True, '{' : True,
'}' : True, '~' : True, '*' : True, '?' : True,
'|' : True, 'amp;' : True, '/' : True
}
return escape_chars.get(character, False)
sanitized = ''
for character in query:
if needs_escaping(character):
sanitized = '\%s' % character
else:
sanitized = character
Комментарии:
1. Внимание будущих читателей: в Elasticsearch есть и другие символы, которые также необходимо экранировать поверх этого: elastic.co/guide/en/elasticsearch/reference/2.3 /… (Это версия v2.3, обратитесь к той, которую вы развернули)
Ответ №1:
Да, эти символы необходимо будет заменить в содержимом, которое вы хотите выполнить для поиска в запросе query_string. Для этого (при условии, что вы используете PyLucene) вы должны уметь использовать QueryParserBase.escape(String)
.
За исключением этого, вы всегда можете адаптировать QueryParserBase.escape
исходный код к своим потребностям:
public static String escape(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i ) {
char c = s.charAt(i);
// These characters are part of the query syntax and must be escaped
if (c == '\' || c == ' ' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':'
|| c == '^' || c == '[' || c == ']' || c == '"' || c == '{' || c == '}' || c == '~'
|| c == '*' || c == '?' || c == '|' || c == 'amp;' || c == '/') {
sb.append('\');
}
sb.append(c);
}
return sb.toString();
}
Комментарии:
1. Код Java помог. Я отредактирую, чтобы включить свой ответ на python, но это было на правильном пути.
2. Когда это условие выполняется? « c == ‘»‘ «
3. @SavvaSergey хотя экранирование двойных кавычек в данном контексте не является строго необходимым, экранированная двойная кавычка по-прежнему будет обрабатываться как обычная двойная кавычка из одного символа.
Ответ №2:
Я адаптировал этот код, который я нашел там:
escapeRules = {' ': r' ',
'-': r'-',
'amp;': r'amp;',
'|': r'|',
'!': r'!',
'(': r'(',
')': r')',
'{': r'{',
'}': r'}',
'[': r'[',
']': r']',
'^': r'^',
'~': r'~',
'*': r'*',
'?': r'?',
':': r':',
'"': r'"',
'\': r'\;',
'/': r'/',
'>': r' ',
'<': r' '}
def escapedSeq(term):
""" Yield the next string based on the
next character (either this char
or escaped version """
for char in term:
if char in escapeRules.keys():
yield escapeRules[char]
else:
yield char
def escapeESArg(term):
""" Apply escaping to the passed in query terms
escaping special characters like : , etc"""
term = term.replace('\', r'\') # escape first
return "".join([nextStr for nextStr in escapedSeq(term)])
Ответ №3:
чтобы ответить на вопрос напрямую, ниже приведено более чистое решение на python, использующее re.sub
import re
KIBANA_SPECIAL = ' - amp; | ! ( ) { } [ ] ^ " ~ * ? : \'.split(' ')
re.sub('([{}])'.format('\'.join(KIBANA_SPECIAL)), r'\1', val)
однако лучшим решением является правильный анализ неверных символов, которые отправляются в elasticsearch:
import six.moves.urllib as urllib
urllib.parse.quote_plus(val)
Комментарии:
1. Пожалуйста, предоставьте более подробную информацию
Ответ №4:
Да, эти символы необходимо будет заменить в содержимом, которое вы хотите найти в запросе query_string.
import re
def escape_elasticsearch_query(query):
return re.sub(
'( |-|=|amp;amp;||||>|<|!|(|)|{|}|[|]|^|"|~|*|?|:|\|/)',
"\\\1",
query,
)