Java. Поиск слов во вводимом тексте на сервере. Идеи для реализации

#java #full-text-search

#java #полнотекстовый поиск

Вопрос:

Например, у меня такая ситуация:

на сервере у нас есть список слов:

 {'word1', 'word2', 'word3', 'word4'}
 

Пользователь отправляет запрос на сервер с некоторым текстом:

 "some text here word1. many many other text word4"
 

Сервер должен обработать этот вводимый текст, найти все слова в этом тексте из списка серверов, отметить эти слова и отправить результирующий текст пользователю:

 "some text here <mark>word1<mark>. many many other text <mark>word4<mark>"
 

Это основная идея, основная концепция. На данный момент я должен реализовать эту логику.

Итак, я прошу вас о помощи.

Мне необходимо определиться с технологиями и инструментами.

Какие инструменты вы можете порекомендовать для этой задачи?

Ответ №1:

Вот наивное решение:

 for (String word : words) {
    text = text.replaceAll(word, "<mark>"  word   "</mark>");
}
 

Лучшее решение должно использовать регулярное выражение, чтобы избежать замены фрагментов слов, например wo<mark>man</mark> . Вы должны создать регулярное выражение, подобное "\b" word "\b" .

Но я бы посоветовал вам проверить готовые к использованию движки, такие как Solr (или Lucine).

Комментарии:

1. Вы также хотели бы проверить наличие двойных совпадений в не наивном подходе. Например, если words они содержатся "trowel", "row" , вы получите дважды вложенные теги, такие как I use my <mark>t<mark>row</mark>el</mark> in my garden. это произойдет даже при улучшении фрагментов слов. И, как ни странно, результат будет меняться в зависимости от порядка следования списка поисковых терминов, что почти наверняка удивительно.

Ответ №2:

Есть много открытых вопросов, например, что именно разделяет «слова». Например. вы хотите выделить «полный» в «полнотекстовом»?

  1. Однако вот действительно простая идея:
  2. Соберите слова сервера в хэш-набор,
  3. Анализируйте каждый запрос, т.Е. Идентифицируйте слова в соответствии с тем, что вы хотите использовать в качестве разделителей. (линейный)
  4. Для каждого токена / слова проверьте членство в HashMap (O(1))
  5. Напишите слово или слово, включающее ваши отмеченные теги, в выходные данные.

Кстати: Lucene, Solr и т. Д. Здесь Не слишком помогут. Конечно, вы можете их использовать, но это просто не имеет смысла. Их сила заключается в создании индекса текста. Текст может означать ОГРОМНЫЕ объемы данных. Набор слов ограничен диктонарием языка. Обычно это шутка по размеру для компьютеров. Простой набор хэшей должен соответствовать вашим потребностям.

Ответ №3:

Самый простой способ добиться этого — использовать String.replaceAll . Вы можете объединить все ключевые слова в одно регулярное выражение и использовать обратную ссылку для включения исходного слова. Если ключевые слова содержат операторы регулярных выражений, вам придется их избегать.

Обычно ошибочно вызывать String.replaceAll в цикле, потому что промежуточные результаты могут содержать совпадение, которого не было во входных данных. В качестве надуманного примера предположим, что я хотел заменить «ab» на «b» и «bb» на «c». Итак, правильным выводом для «bab» будет «bb». Однако «bab».replaceAll(«ab», «b»).replaceAll(«bb», «c») — это «c». По той же причине вы не хотели бы использовать String.replace в цикле, хотя это кажется самым простым способом выполнения поставленной задачи.

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