Elasticsearch. Как сохранить аббревиатуры в верхнем регистре при использовании фильтра нижнего регистра?

Как в Elasticsearch 2.x отличить аббревиатуру «CAN» от общеупотребительного английского слова «can», все еще используя фильтр «нижний регистр» в моем анализаторе (используется, чтобы поиск не учитывал регистр)?

Пользовательский анализатор, который я использую:

"analyzer": {
    "tight": {
        "type": "custom",
        "tokenizer": "standard",
        "stopwords": "_english_",
        "filter": ["lowercase", "asciifolding"]
    }
}

В индексное время, когда аббревиатура «CAN» в верхнем регистре попадает в мой анализатор, она становится английским словом «can». Затем, когда я ищу «CAN», я получаю все документы, в которых есть английское слово «can». Мне нужны только документы, содержащие слово «CAN» в верхнем регистре. Вероятно, есть и другие аббревиатуры, которые попадают в аналогичную схему.

Каков наилучший способ решить эту проблему?


person Redtopia    schedule 04.08.2016    source источник


Ответы (1)


Один из способов добиться этого — создать еще один анализатор без фильтра токена lowercase и использовать этот анализатор в подполе вашего основного поля. Это выглядит так:

Создайте индекс с двумя анализаторами tight и tight_acronym. Первый назначается подполю field, а второй — подполю field.acronyms:

PUT index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "tight": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "asciifolding"
          ]
        },
        "tight_acronym": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "asciifolding"
          ]
        }
      }
    }
  },
  "mappings": {
    "test": {
      "properties": {
        "field": {
          "type": "string",
          "analyzer": "tight",
          "fields": {
            "acronyms": {
              "type": "string",
              "analyzer": "tight_acronym"
            }
          }
        }
      }
    }
  }
}

Затем индексируем два документа:

PUT index/test/1
{ "field": "It is worth CAN 300" }
PUT index/test/2
{ "field": "can you do it?" }

Затем, если вы выполните поиск CAN (в подполе), вы получите первый документ

POST index/test/_search
{
  "query": {
    "match": {
      "field.acronyms": "CAN"
    }
  }
}

И если вы ищете can (в основном поле), вы получите второй документ

POST index/test/_search
{
  "query": {
    "match": {
      "field": "can"
    }
  }
}
person Val    schedule 15.08.2016
comment
Первая проблема, которую я вижу, заключается в том, что вам также придется искать поле с фильтром нижнего регистра, чтобы выполнить совпадение без учета регистра, а это означает, что аббревиатура CAN всегда будет соответствовать этому первому критерию. Решение, над которым я работаю, добавляет char_filter, который заменяет аббревиатуру CAN на ccaann, а затем у меня есть список замены акронимов в моем коде, который заменяет все вхождения моих акронимов их эквивалентом в нижнем регистре. - person Redtopia; 17.08.2016
comment
Справедливо. Если вы пойдете по этому пути, я предлагаю использовать вместо этого используйте фильтр токенов синонимов, чтобы вам вообще не нужно было изменять код клиента. Вам просто нужно отредактировать файл синонимов, и все готово. - person Val; 17.08.2016
comment
Это интересная идея. Итак, если CAN в конечном итоге будет проиндексирован как ccaann, то моими синонимами будут CAN, ccaann, это правильно? - person Redtopia; 17.08.2016
comment
Да, это правильно. Вы также должны убедиться, что ignore_case установлено на false, иначе can и CAN будут считаться одним и тем же. - person Val; 17.08.2016