Статьи

Выделение ключевых слов и расчет сходства между текстовым содержанием

Фон

Веб-приложения становятся умнее. Прошли те времена, когда, чтобы воспользоваться услугой с сайта, пользователю пришлось заполнить гигантскую форму. Допустим, у вас есть веб-сайт для любителей книг. До появления веб 2.0 такие сайты, как эти, задавали пользователю все вопросы в форме, например, возраст, книги, которые они читают, типы книг, которые им нравятся, языковые предпочтения, предпочтения авторов и т. Д. В наши дни принято задавать вопросы пользователю: написать абзац на себя (профиль). В этой заметке пользователь выражает некоторые подробности, но проблема в том, как мы извлекаем полезную информацию из такого текста в свободной форме, и более того, как мы находим пользователя, который имеет аналогичный интерес?

Этот вариант использования стал настолько распространенным, что каждый Java-разработчик должен знать некоторые хитрости по извлечению информации из текста. В этой статье я расскажу вам об одном простом, но эффективном способе сделать это.

Процессы извлечения информации из текста

  1. Фильтр слов : читать текстовое содержание слово за словом и удалять ненужные слова. Как часть этого состояния фильтрации, удалите все часто используемые английские слова. Можно также применять правила цензуры и удалять откровенно сексуальные слова или ненавистнические высказывания и т. Д.
  2. Выполнить Stemming: слова типа «поиск» или «поиск» или «поиск», которые все означают «поиск». Этот процесс приведения слова к своему корню называется stemming.
  3. Вычислить сходство : после первых двух шагов у нас теперь есть набор ключевых слов, которые действительно представляют оригинальный текст (профиль пользователя в этом примере). Мы можем рассматривать эти ключевые слова как набор уникальных слов. Чтобы вычислить сходство между двумя пользовательскими профилями, было бы лучше, если бы мы представили сходство в виде числа, которое представляет, насколько сходны два содержимого в масштабе от 0 (не похоже) до 1 (полностью похоже). Одним из способов достижения этого является вычисление индекса Жакара, который используется для вычисления сходства или разнообразия множеств.
1
Jaccard index J(A,B) = |A∩B|/| A⋃B|

где A и B — множества, а J (A, B) лежит в диапазоне от 0 до 1.

Детали реализации

Исходя из изложенных выше моментов, можно разработать библиотеку для извлечения ключевых слов и вычисления сходства. Однако Apache Lucene — это java-библиотека, которая имеет множество API для выполнения извлечения ключевых слов. Вот краткое описание различных важных областей этого API.

Tokenizer

Tokenizer разбивает ваш текст на куски. Существуют разные токенизаторы, и в зависимости от того, какой токенайзер вы используете, вы можете получать разные потоки выходных токенов ( последовательности фрагментов текста).

парадигматические

Стеммеры используются, чтобы получить основу для рассматриваемого слова. Это сильно зависит от используемого языка. Такие слова, как «моряк», «поиск», «поиск» и т. Д. Происходят от корневого слова «поиск». В поле поиска информации очень полезно, если мы доберемся до корневых слов, так как они уменьшают шум, и с меньшим количеством слов мы все еще можем нести цель документа. Одним из известных алгоритмов стеммера является алгоритм Портера Стеммера.

TokenFilter

Tokenfilter может быть применен к выходу токенайзера для нормализации или фильтрации токенов. Как и LowerCaseFilter, который нормализует текст токена в нижний регистр или стоп-фильтр, который подавляет наиболее часто встречающиеся и почти бесполезные слова. Опять же, это сильно зависит от языка. Для английского языка эти стоп-слова — «а», «я», «быть», «иметь» и т. Д.

анализатор

Анализатор — это класс более высокого уровня, который использует токены для получения токенов из входных данных, использует стеммеры для уменьшения токена, использует фильтры для подавления / нормализации токенов. Это класс, который склеивает остальные три основных компонента. Разные анализаторы используют разные комбинации токенизаторов и фильтров. Например, StandardAnalyzer использует StandardTokenizer для извлечения токенов из строки, передает их через LowerCaseFilter для преобразования токенов в нижний регистр, а затем передает поток токенов через StopFilter для удаления наиболее часто используемых английских слов. Он не выполняет стемминг по умолчанию. Можно разработать собственный анализатор, смешивая и подбирая токенизатор и токен-фильтры по необходимости.

Код пройти через

Исходный код этого примера можно получить по адресу https://github.com/shamikm/simility . Ниже приведено описание шагов:

  1. Создайте собственный анализатор, который выполняет следующие шаги:
    • Токенизируйте английские слова на основе пробела, запятой, точки и т. Д. Используйте StandardTokenizer для этой задачи.
    • Преобразуйте токены в нижний регистр, используя LowerCaseFilter
    • Остановите общие английские слова, используя StopFilter
    • Английские слова в стебле с помощью Porter Stemmer

    Из класса StemmAnalyzer:

    1
    2
    3
    4
    5
    6
    7
    8
    @Override
        public TokenStream tokenStream(String fieldName, Reader reader) {
          (a)..  final StandardTokenizer src = new StandardTokenizer(matchVersion, reader);
                 TokenStream tok = new StandardFilter(matchVersion, src);
          (b)..  tok = new LowerCaseFilter(matchVersion, tok);
          (c)..  tok = new StopFilter(matchVersion, tok, getStopWords());
          (d)..  return new PorterStemFilter(tok);
        }
  2. Когда у нас есть набор слов, легко вычислить сходство между двумя наборами.

    Из класса JaccardIndexBasedSogeneity:

    1
    2
    3
    4
    5
    6
    7
    8
    public double calculateSimilarity(String oneContent, String otherContet) {
            Set<String> keyWords1 = keywordGenerator.generateKeyWords(oneContent);
            Set<String> keyWords2 = keywordGenerator.generateKeyWords(otherContet);
            Set<String> denominator = Sets.union(keyWords1,keyWords2);
            Set<String> numerator = Sets.intersection(keyWords1,keyWords2);
     
            return denominator.size()>0? (double)numerator.size()/(double)denominator.size() : 0;
        }

Вот пример тестового примера, чтобы продемонстрировать, как работает код:

1
2
3
4
5
6
7
8
@Test
    public void calculateSim(){
        SimilarityCalculator calculator = new JaccardIndexBasedSimilarity();
        Assert.assertEquals(calculator.calculateSimilarity("They Licked the platter clean","Jack Sprat could eat no fat"),0.0);
        //1(lamb) out of 6(littl,lamb,mari,had,go,sure) words are same
        Assert.assertEquals(calculator.calculateSimilarity("Mary had a little lamb", "The lamb was sure to go."), 0.16, 0.02);
        Assert.assertEquals(calculator.calculateSimilarity("Mary had a little lamb","Mary had a little lamb"),1.0);
    }

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

Вывод

Извлечение информации из текста является распространенным случаем в наши дни. Наличие базовых знаний в этой критической области полезно для любого разработчика, и в этой статье мы рассмотрели, как можно эффективно использовать API Apache Lucene для извлечения ключевых слов и вычисления сходства текста.

Ресурсы: