# Подсветка результатов поиска по полю с фильтром word\_delimiter не правильно работает

**URL:** https://discuss.elastic.co/t/word-delimiter/170701
**Category:** Вопросы на русском языке
**Created:** [March 4, 2019, 10:03am UTC](https://discuss.elastic.co/t/word-delimiter/170701 "2019-03-04T10:03:13Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 4, 2019, 10:03am UTC](https://discuss.elastic.co/t/word-delimiter/170701/1 "2019-03-04T10:03:13Z")

</div>

Добрый день,  
Есть текст, в котором символы, цифры и буквы смешиваются в одно слово и с помощью фильтра word\_delimiter хотел это разделить, но поломалась подсветка результатов.

> **Настройки индекса и запросы поиска**
>
> ```
> DELETE test
> 
> PUT test
> {
> "settings": {
> "number_of_shards": 1,
> "analysis": {
> "normalizer": {
> "lowercase": {
> "type": "custom",
> "filter": "lowercase"
> }
> },
> "filter": {
> "word_delimiter": {
> "type": "word_delimiter_graph",
> "preserve_original": true,
> "catenate_all": true
> }
> },
> "tokenizer": {
> "my_ngram_tokinizer": {
> "type": "edge_ngram",
> "min_gram": 1,
> "max_gram": 50,
> "token_chars": [
> "letter",
> "digit",
> "symbol",
> "punctuation"
> ]
> }
> },
> "char_filter": {
> "char_mapping": {
> "type": "mapping",
> "mappings": [
> "Ё => Е",
> "ё => е"
> ]
> }
> },
> "analyzer": {
> "my_ngram": {
> "type": "custom",
> "tokenizer": "my_ngram_tokinizer",
> "char_filter": [
> "html_strip",
> "char_mapping"
> ],
> "filter": [
> "lowercase",
> "word_delimiter"
> ]
> },
> "my_search": {
> "tokenizer": "whitespace",
> "char_filter": [
> "html_strip"
> ],
> "filter": [
> "lowercase"
> ]
> }
> }
> }
> },
> "mappings": {
> "_doc": {
> "properties": {
> "title": {
> "type": "keyword",
> "normalizer": "lowercase",
> "fields": {
> "ngram": {
> "type": "text",
> "analyzer": "my_ngram",
> "search_analyzer": "my_search"
> }
> }
> }
> }
> }
> }
> }
> 
> PUT test/_doc/1
> {
> "title" : "Сделка №25"
> }
> 
> PUT test/_doc/2
> {
> "title" : "Import46 (copy).csv"
> }
> 
> GET test/_search
> {
> "query": {
> "bool": {
> "should": [
> {
> "match": {
> "title.ngram": {
> "query": "Сделка №2",
> "operator": "AND"
> }
> }
> }
> ]
> }
> },
> "highlight": {
> "fields": {
> "*": {}
> }
> }
> }
> 
> GET test/_search
> {
> "query": {
> "bool": {
> "should": [
> {
> "match": {
> "title.ngram": {
> "query": "Import46",
> "operator": "AND"
> }
> }
> }
> ]
> }
> },
> "highlight": {
> "fields": {
> "*": {}
> }
> }
> }
> 
> ```

Подскажите, как починить подсветку ?

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 4, 2019, 5:37pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/2 "2019-03-04T17:37:43Z")

</div>

Подсветка работает нормально, это анализатор весь перекрученный и выдает ерунду. Если посмотреть, что происходит с токенами:

```auto
POST test/_analyze
{
  "text": ["Import46 (copy).csv"],
  "analyzer": "my_ngram"
}

```

то вы получите кроме всего прочего:

```auto
    {
      "token" : "import46",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "word",
      "position" : 8,
      "positionLength" : 2
    },

```

Другими словами, анализатор утверждает, что `import46` начинается на позиции 6 и имеет длину в 2 символа, что у вас и подсвечивается.

Вообще, graph фильтры - дело [сложное](http://blog.mikemccandless.com/2012/04/lucenes-tokenstreams-are-actually.html), особенно, если пытаться применять их при индексации вместо поиска да еще и с N-граммами. Я могу объяснить почему это решение работать не будет, но я не могу понять, что вы хотите добиться этим анализатором, поэтому другие решения подсказать не могу.

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 5, 2019, 2:38am UTC](https://discuss.elastic.co/t/word-delimiter/170701/3 "2019-03-05T02:38:24Z")

</div>

Хочется добиться отделения символов, цифр и букв друг от друга, что бы слова:  
"Сделка №25" можно было найти по "Сделка" , "Сделка 25" , "25 Сделка" , "Сделка №25"  
"Import46 (copy).csv" по "import 46", "import46", "46 импорт",  
Кроме использования word\_delimiter\_graph я не нашёл способа это сделать

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 5, 2019, 4:46pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/4 "2019-03-05T16:46:51Z")

</div>

> Хочется добиться отделения символов, цифр и букв друг от друга, что бы слова

Это только часть требований, которая не объясняет зачем нужен ngram.

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 5, 2019, 5:55pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/5 "2019-03-05T17:55:09Z")

</div>

Точно, забыл про ngram написать.  
Ngram нам нужен для поиска с автокомплитом. Он у нас используется практически во всех полях содержащих небольшие строки текста. Это названия товаров, названия задач, названия сделок, имена клиентов, номера телефонов, адреса почты, обычно 50-70 символов.

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 5, 2019, 7:27pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/6 "2019-03-05T19:27:34Z")

</div>

> Ngram нам нужен для поиска с автокомплитом

И как это должно работать с word delimiter?

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 5, 2019, 8:21pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/7 "2019-03-05T20:21:53Z")

</div>

Как пример в случае автокомплита:  
"import46" находим по "imp", "impo", "import", "import46", "import 46", "46 imp", "46 import"  
"Сделка №25" находим по "сдел", "сделк", "сделка", "сделка 2", "сделка 25", "сделка №2", "сделка №25", "25 сдел", "25 сделка"

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 5, 2019, 8:54pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/8 "2019-03-05T20:54:36Z")

</div>

А как насчет "сдел 2" и "сдел2" ?

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 6, 2019, 1:58am UTC](https://discuss.elastic.co/t/word-delimiter/170701/9 "2019-03-06T01:58:02Z")

</div>

"сдел2" скорее всего пока не нужно, а вот "сдел 2" как я понимаю, это небольшой приятный бонус от использования edge\_ngram.  
Судя по логам, так ещё не пробовали искать и пока не понятно, нужно ли будет.

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 6, 2019, 3:38pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/10 "2019-03-06T15:38:06Z")

</div>

Ну если Вы ничего о дополнительных требованиях не умолчали, то как-то так:

```auto
DELETE test

PUT test
{
  "settings": {
    "number_of_shards": 1,
    "analysis": {
      "normalizer": {
        "lowercase": {
          "type": "custom",
          "filter": "lowercase"
        }
      },
      "char_filter": {
        "char_mapping": {
          "type": "mapping",
          "mappings": [
            "Ё => Е",
            "ё => е"
          ]
        }
      },
      "filter": {
        "my_ngram_filter": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 50
        },
        "my_word_delimiter_index": {
          "type": "word_delimiter",
          "preserve_original": false
        } ,
        "my_word_delimiter_search": {
          "type": "word_delimiter_graph",
          "preserve_original": false
        }
      },
      "analyzer": {
        "my_index": {
          "type": "custom",
          "char_filter": [
            "html_strip",
            "char_mapping"
          ],
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "my_word_delimiter_index",
            "my_ngram_filter"
          ]
        },
        "my_search": {
          "type": "custom",
          "char_filter": [
            "char_mapping"
          ],
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "my_word_delimiter_search"
          ]
        }
      }
    }
  },
  "mappings": {
    "_doc": {
      "properties": {
        "title": {
          "type": "keyword",
          "normalizer": "lowercase",
          "fields": {
            "ngram": {
              "type": "text",
              "analyzer": "my_index",
              "search_analyzer": "my_search"
            }
          }
        }
      }
    }
  }
}

PUT test/_doc/1
{
  "title" : "Сделка №25"
}

PUT test/_doc/2
{
  "title" : "Import46 (copy).csv"
}

GET test/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title.ngram": {
              "query": "Сделка №2",
              "operator": "AND"
            }
          }
        }
      ]
    }
  },
  "highlight": {
    "fields": {
      "*": {}
    }
  }
}

GET test/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title.ngram": {
              "query": "Import46",
              "operator": "AND"
            }
          }
        }
      ]
    }
  },
  "highlight": {
    "fields": {
      "*": {}
    }
  }
}

```

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 7, 2019, 5:26am UTC](https://discuss.elastic.co/t/word-delimiter/170701/11 "2019-03-07T05:26:03Z")

</div>

Прошу прощения, я забыл упомянуть, что ещё подсвечивать нужно только то, что ввели, например ввели "сдел" подсветило `"<em>Сдел</em>ка №25"`, а сейчас подсвечивает всё слово `"<em>Сделка</em>"`.

Насколько я понимаю, это из за токенайзера "whitespace". Попробовал заменить его на токенайзер edge\_ngram, убрав "my\_ngram\_filter", но при добавлении документа с "Import46 (copy).csv" выскакивает ошибка:

> startOffset must be non-negative, and endOffset must be \>= startOffset, and offsets must not go backwards startOffset=0,endOffset=6,lastStartOffset=6 for field 'title.ngram'

---

<div class="post-metadata">

### Author: ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)
#### Post date: [March 7, 2019, 2:19pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/12 "2019-03-07T14:19:13Z")

</div>

> Прошу прощения, я забыл упомянуть,

Ну вот, началось 😄 Подсветка происходит по позициям. Поэтому для того, чтобы подсвечивать часть термина, эта часть должна иметь свою собственную позицию. Этого можно добиться, поместив используя ngram токенизатор, но поскольку поиск по фразам тоже использует позиции, он поломается. Так что, если нужно искать по фразам, то можно искать как показано выше, а подсвечивать по полю индексированному вот так:

```auto
PUT test
{
  "settings": {
    "number_of_shards": 1,
    "analysis": {
      "normalizer": {
        "lowercase": {
          "type": "custom",
          "filter": "lowercase"
        }
      },
      "char_filter": {
        "digit_after": {
          "type": "pattern_replace",
          "pattern": "(\\D)(\\d)",
          "replacement": "$1 $2"
        },
        "digit_before": {
          "type": "pattern_replace",
          "pattern": "(\\d)(\\D)",
          "replacement": "$1 $2"
        },
        "char_mapping": {
          "type": "mapping",
          "mappings": [
            "Ё => Е",
            "ё => е"
          ]
        }
      },
      "tokenizer": {
        "my_ngram_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 1,
          "max_gram": 50,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      },
      "filter": {
        "my_word_delimiter_search": {
          "type": "word_delimiter_graph",
          "preserve_original": false
        }
      },
      "analyzer": {
        "my_index": {
          "type": "custom",
          "char_filter": [
            "html_strip",
            "char_mapping",
            "digit_before",
            "digit_after"
          ],
          "tokenizer": "my_ngram_tokenizer",
          "filter": [
            "lowercase"
          ]
        },
        "my_search": {
          "type": "custom",
          "char_filter": [
            "char_mapping"
          ],
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "my_word_delimiter_search"
          ]
        }
      }
    }
  },
  "mappings": {
    "_doc": {
      "properties": {
        "title": {
          "type": "keyword",
          "normalizer": "lowercase",
          "fields": {
            "ngram": {
              "type": "text",
              "analyzer": "my_index",
              "search_analyzer": "my_search"
            }
          }
        }
      }
    }
  }
}

```

---

<div class="post-metadata">

### Author: ![bio](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/bio/32/76409_2.png) [@bio](https://discuss.elastic.co/u/bio)
#### Post date: [March 7, 2019, 2:23pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/13 "2019-03-07T14:23:12Z")

</div>

Спасибо! Работает, буду тестировать 🙂

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)
#### Post date: [April 4, 2019, 2:23pm UTC](https://discuss.elastic.co/t/word-delimiter/170701/14 "2019-04-04T14:23:15Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
