Экранирование специальных символов в elasticsearch

#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,
    )