elasticsearch query_string обрабатывает специальные символы - PullRequest
0 голосов
/ 06 мая 2020

Моя база данных синхронизирована c с Elasticsearch, чтобы оптимизировать результаты поиска и быстрее запрашивать.

У меня проблема с запросом пользователей, я хочу, чтобы мои пользователи выглядели с помощью запроса, это может быть часть имени, телефона, IP, ...

Мой фактический запрос

query_string: { fields: ['id', 'email', 'firstName', 'lastName', 'phone', 'ip'], query: `*${escapeElastic(req.query.search.toString().toLowerCase())}*`}

Где req.query.search - мой поиск, а escapeElasti c исходит из модуля узла elasticsearch-sanitize потому что у меня были проблемы с некоторыми символами.

У меня проблема, например, если я запрашиваю ipv6, у меня будет query: '*2001\\:0db8*', но он ничего не найдет в базе данных, а должен

Другая проблема, если у меня есть кто-то с firstName john-doe, мой запрос будет query: '*john\\-doe*', и он не найдет никакого результата.

Кажется, что escape предотвращает ошибки запроса, но создает некоторые проблемы в моем случае.

Я не знаю, лучше ли query_string выполнить мой запрос, я открыт для предложений по оптимизации этого запроса

Спасибо

1 Ответ

1 голос
/ 06 мая 2020

Я подозреваю, что анализатор на ваших полях - standard или аналогичный. Это означает, что символы типа : и - были удалены:

GET _analyze
{
  "text": "John-Doe",
  "analyzer": "standard"
}

с отображением

{
  "tokens" : [
    {
      "token" : "john",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "doe",
      "start_offset" : 5,
      "end_offset" : 8,
      "type" : "<ALPHANUM>",
      "position" : 1
    }
  ]
}

Давайте создадим наш собственный анализатор, который сохранит специальные символы, но строчные буквы для всех остальных символов одновременно:

PUT multisearch
{
  "settings": {
    "analysis": {
      "analyzer": {
        "with_special_chars": {
          "tokenizer": "whitespace",
          "filter": [
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "firstName": {
        "type": "text",
        "fields": {
          "with_special_chars": {
            "type": "text",
            "analyzer": "with_special_chars"
          }
        }
      },
      "ip": {
        "type": "ip",
        "fields": {
          "with_special_chars": {
            "type": "text",
            "analyzer": "with_special_chars"
          }
        }
      }
    }
  }
}

Прием двух образцов документов:

POST multisearch/_doc
{
  "ip": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
}

POST multisearch/_doc
{
   "firstName": "John-Doe"
}

и применение вашего запроса сверху:

GET multisearch/_search
{
  "query": {
    "query_string": {
      "fields": [
        "id",
        "email",
        "firstName.with_special_chars",
        "lastName",
        "phone",
        "ip.with_special_chars"
      ],
      "query": "2001\\:0db8* OR john-*"
    }
  }
}

оба совпадения возвращаются.


Два замечания: 1) обратите внимание, что мы искали .with_special_chars вместо основных полей и 2) я удалил ведущий подстановочный знак из ip - это очень неэффективно.


Последние подсказки, так как вы просили предложения по оптимизации: запрос можно переписать как

GET multisearch/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "id": "tegO63EBG_KW3EFnvQF8"
          }
        },
        {
          "match": {
            "email": "john@doe.com"
          }
        },
        {
          "match_phrase_prefix": {
            "firstName.with_special_chars": "john-d"
          }
        },
        {
          "match_phrase_prefix": {
            "firstName.with_special_chars": "john-d"
          }
        },
        {
          "match": {
            "phone.with_special_chars": "+151351"
          }
        },
        {
          "wildcard": {
            "ip.with_special_chars": {
              "value": "2001\\:0db8*"
            }
          }
        }
      ]
    }
  }
}
  1. Частичное совпадение id, вероятно, излишество - либо term ловит или нет
  2. email может быть просто match ed
  3. first- & lastName: я подозреваю, что match_phrase_prefix более эффективен, чем wildcard или regexp, поэтому я бы go с этим (если вам не нужен ведущий *)
  4. phone может быть match ed, но убедитесь, что специальные символы тоже могут быть сопоставлены (если вы используете формат int'l)
  5. используйте wildcard для ip - тот же синтаксис, что и в строке запроса

Попробуйте описанное выше и посмотрите, заметите ли вы улучшения скорости!

...