Пользовательский токенизатор elasticsearch

Привыкайте писать вместе! Это 13-й день моего участия в «Ежедневном новом плане Nuggets · Апрельское обновление»

предисловие

Наследовать последний elasticsearch с каналом для обработки полей массива. Фактически, из-за невнимательности в начале конфигурация массива в поле objField не была включена в файле конфигурации канала, в результате чего поле, которое я изначально ожидал отобразить как массив, было успешно сопоставлено со строковым полем. Поэтому возникает вопрос. Например, у нас есть объект продукта в elasticsearch, который может соответствовать нескольким меткам.Нам нужно сохранить связанный идентификатор метки, китайскую метку и английскую метку для документа продукта. По какой-то причине эти поля, которые должны были храниться как массивы, были сжаты в строки, объединенные знаками препинания (например, точками с запятой).

{
 "labels": "1;2;3",
 "labels_cn": "历史;中国;精品课",
 "labels_en": "history;china;class quality"
 }
{
  "label_cn_names": {
       "type": "text"
   },
  "label_en_names": {
       "type": "text"
   },
  "labels": {
       "type": "text"
   }
}
复制代码

Выше приведен фрагмент хранилища документов, видно что 1. Хранилище строковое 2. Тип поля текстовый.

Текст будет сегментирован при поиске.Наше требование состоит в том, что, например, я ищу по идентификатору тега или китайскому тегу или английскому тегу.

31 = "Привязать объект к 31-му идентификатору метки

Китай = "Связать китайскую бирку является объектом Китая

Китай => Получить связанный английский тег является объектом Китая.

Я думаю, что если соответствующий запрос похож на неоднозначный, если тег подвержен ложным срабатываниям, например, я ищу сумку на английском языке, и тег «школа и сумка» также будет возвращен; на китайском я поиск страны, и тег "Китай" также будет возвращен. Поскольку тип текста будет проанализирован и сегментирован во время поиска, а стандартный токенизатор по умолчанию или токенизатор ik будет работать неправильно после сегментации слов. Для этой разделенной строки мы также хотим точно соответствовать каждому отдельному значению в «массиве». Так стоит ли начинать с сегментации слов?Например, по разделителю каждая сегментация слова является каждым значением массива, поэтому даже если сегментация слова выполняется анализатором во время поиска, значение каждого слова сегментации может быть полностью совпало.

обычай причастие

Прежде всего, давайте кратко объясним, что анализатор в elasticsearch состоит из 3 частей: 1, 0 или более фильтров символов 2, токенизатор 3, 0 или более фильтров токенов Все, что нам нужно сделать, это создать токенизатор, официальный предоставляет случай токенизатора шаблона. Сегментация шаблона относится к разделению текста с помощью регулярных выражений.

PUT my-index-000001
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "pattern",
          "pattern": ","
        }
      }
    }
  }
}

POST my-index-000001/_analyze
{
  "analyzer": "my_analyzer",
  "text": "comma,separated,values"
}
复制代码

例如这是一个逗号的分词器。所有文本会按照逗号分隔。我们给我们的索引创建一个分号的分词器。 下面来看下比较,首先是没有用自定义分词器的

{
    "query":{
        "match":{
            "labels_cn": "课"
        }
    }
}
--------------------
 "hits": [
            {
                "_index": "book",
                "_type": "_doc",
                "_id": "HjPUJ4ABRHGvpe9lz-Be",
                "_score": 0.2876821,
                "_source": {
                    "book_name": "畅销书",
                    "labels": "1;2;3",
                    "labels_cn": "历史;中国;精品课",
                    "labels_en": "history;china;class quality"
                }
            }
        ]
复制代码

可以看到有结果返回,可以理论上只有搜索精品课才能返回。这是由于labels_cn被分词了,例如你是用了ik,那么很有可能分词为精品、课。所以就会被误匹配。 下面我们增加自定义分词器,然后再进行同样的查询

{
    "query":{
        "match":{
            "labels_cn": "课"
        }
    }
}
------------
"hits": {
        "total": {
            "value": 0,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    }
复制代码

很神奇,没有返回。为了方便理解,我们测试下分词器的作用,使用_analyze API

{
    "analyzer": "semicolon_analyzer",
    "text": "历史;中国;精品课"
}
{
    "tokens": [
        {
            "token": "历史",
            "start_offset": 0,
            "end_offset": 2,
            "type": "word",
            "position": 0
        },
        {
            "token": "中国",
            "start_offset": 3,
            "end_offset": 5,
            "type": "word",
            "position": 1
        },
        {
            "token": "精品课",
            "start_offset": 6,
            "end_offset": 9,
            "type": "word",
            "position": 2
        }
    ]
}
复制代码

看到文本只会按照分号进行分词。所以也只可能被完整的标签值匹配。下面输入完整的标签来搜索

{
    "query":{
        "match":{
            "labels_cn": "精品课"
        }
    }
}
----------
 "hits": [
            {
                "_index": "book1",
                "_type": "_doc",
                "_id": "HzPcJ4ABRHGvpe9lHeCW",
                "_score": 0.18232156,
                "_source": {
                    "book_name": "畅销书",
                    "labels": "1;2;3",
                    "labels_cn": "历史;中国;精品课",
                    "labels_en": "history;china;class quality"
                }
            }
            ]
复制代码

可以看到符合我们的预期了。

рекомендация

отjuejin.im/post/7086662432231260197
рекомендация