Анализ ключевых слов в PHP


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

Получить все слова, их плотность и отобразить их относительно просто, но это дает очень искаженные результаты (например, очень высокий рейтинг стоп-слов).

В принципе, мой вопрос таков: как я могу создать инструмент анализа ключевых слов в PHP, который приведет к списку, правильно упорядоченному по важности слов?

Author: mschr, 2012-05-23

5 answers

В последнее время я сам работаю над этим, и я постараюсь объяснить, что я сделал как можно лучше.

Шаги

  1. Текст фильтра
  2. Разделить на слова
  3. Удалить 2 символьных слова и стоп-слова
  4. Определить частоту слов + плотность
  5. Определите значимость слова
  6. Определение контейнеров слов
    1. Название
    2. Мета-описание
    3. URL-АДРЕС
    4. Заголовки
    5. Мета ключевые слова
  7. Вычислить значение ключевого слова

1. Текст фильтра

Первое, что вам нужно сделать, это отфильтровать, чтобы убедиться в правильности кодировки, поэтому преобразуйте в UTF-8:

iconv ($encoding, "utf-8", $file); // where $encoding is the current encoding

После этого вам нужно удалить все html-теги, знаки препинания, символы и цифры. Поищите функции о том, как это сделать в Google!

2. Разделить на слова

$words = mb_split( ' +', $text );

3. Удалить 2 символьных слова и стоп-слова

Любое слово, состоящее из 1 или 2 персонажи не будут иметь никакого значения, поэтому мы удаляем их все.

Чтобы удалить стоп-слова, нам сначала нужно определить язык. Есть несколько способов, которыми мы можем это сделать: - Проверка HTTP-заголовка на языке содержимого - Проверка атрибута lang="" или xml:lang="" - Проверка языка и содержимого - Теги метаданных на языке Если ни один из них не установлен, вы можете использовать внешний API, такой как AlchemyAPI.

Вам понадобится список стоп-слов для каждого языка, который можно легко найдено в Интернете. Я использовал этот: http://www.ranks.nl/resources/stopwords.html

4. Определите частоту слов + плотность

Чтобы подсчитать количество вхождений в каждое слово, используйте следующее:

$uniqueWords = array_unique ($keywords); // $keywords is the $words array after being filtered as mentioned in step 3
$uniqueWordCounts = array_count_values ( $words );

Теперь пройдитесь по массиву $uniquewords и вычислите плотность каждого слова следующим образом:

$density = $frequency / count ($words) * 100;

5. Определите значимость слова

Значение слова определяется положением слов в тексте. Например, второе слово в первое предложение, вероятно, более важно, чем 6-е слово в 83-м предложении.

Чтобы вычислить его, добавьте этот код в тот же цикл, что и на предыдущем шаге:'

$keys = array_keys ($words, $word); // $word is the word we're currently at in the loop
$positionSum = array_sum ($keys) + count ($keys);
$prominence = (count ($words) - (($positionSum - 1) / count ($keys))) * (100 /   count ($words));

6. Определение контейнеров слов

Очень важной частью является определение того, где находится слово - в названии, описании и многом другом.

Во-первых, вам нужно захватить заголовок, все теги метаданных и все заголовки, используя что-то вроде DOMDocument или phpQuery (не пытайтесь использовать регулярное выражение!) Тогда ты нужно проверить, в том же цикле, содержат ли они слова.

7. Вычислить значение ключевого слова

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

$value = (double) ((1 + $density) * ($prominence / 10)) * (1 + (0.5 * count ($containers)));

Этот расчет далек от совершенства, но он должен дать вам достойные результаты.

Заключение

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

N.B. Да, это было вдохновлено сегодняшним постом в блоге об ответах на ваши собственные вопросы!

 49
Author: Jeroen, 2012-05-31 16:57:29

В вашем алгоритме отсутствует одна вещь - анализ, ориентированный на документы (если вы по какой-то причине не опустили его намеренно).

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

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

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

 4
Author: Stan, 2012-05-31 20:03:20

Это, вероятно, небольшой вклад, но, тем не менее, я упомяну об этом.

Оценка контекста

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

Частотная очистка

Обнаружение стоп-слов на основе язык может сработать, но, возможно, вы могли бы рассмотреть возможность использования колоколообразной кривой, чтобы определить, какие частоты/плотности слов являются слишком экстравагантными (например, полоса ниже 5 % и выше 95 %). Затем примените оценку к оставшимся словам. Это не только предотвращает стоп-слова, но и злоупотребление ключевыми словами, по крайней мере в теории:)

 4
Author: Ja͢ck, 2012-06-01 14:28:03

@уточнение "Шагов"

Что касается выполнения этих многих шагов, я бы выбрал немного "улучшенное" решение, объединив некоторые из ваших шагов вместе.

Не уверен, что полный лексер лучше, хотя, если вы спроектируете его идеально в соответствии с вашими потребностями, например, ищите только текст в hX и т. Д. Но вы должны были бы иметь в виду _серьезный бизнес, так как его реализация может стать головной болью. Хотя я выскажу свою точку зрения и скажу, что решение Flex/Bison в другой язык (PHP предлагает плохую поддержку, так как это язык такого высокого уровня) был бы "безумным" повышением скорости.

Однако, к счастью, libxml предоставляет великолепные функции, и, как должно быть показано ниже, в конечном итоге у вас будет несколько шагов в одном. Перед тем, как приступить к анализу содержимого, настройте язык (стоп-слова), уменьшите набор списков узлов и работайте оттуда.

  1. загрузить полную страницу в
  2. определение языка
  3. извлекать только <body> в отдельное поле
  4. освободите немного памяти от <head> и других подобных, напримерunset($fullpage);
  5. запустите свой алгоритм (если pcntl - хост linux - доступен, разветвление и выпуск браузера - хорошая функция)

При использовании парсеров DOM следует понимать, что настройки могут вводить дополнительную проверку атрибутов href и src в зависимости от библиотеки (например, parse_url и likes)

Еще один способ получить информацию о времени ожидания/потреблении памяти - вызвать php-cli (также работает для хоста Windows) и "продолжайте заниматься бизнесом" и начните следующий документ. Смотрите этот вопрос для получения дополнительной информации.

Если вы немного прокрутите вниз, посмотрите на предлагаемую схему - при первоначальном обходе в базу данных будет помещено только тело (и дополнительно lang в вашем случае), а затем запустите cron-скрипт, заполнив ft_index, используя следующую функцию

    function analyse() {
        ob_start(); // dont care about warnings, clean ob contents after parse
        $doc->loadHTML("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"/></head><body><pre>" . $this->html_entity_decode("UTF-8") . "</pre></body>");
        ob_end_clean();
        $weighted_ft = array('0'=>"",'5'=>"",'15'=>"");

        $includes = $doc->getElementsByTagName('h1');
        // relevance wieght 0
        foreach ($includes as $h) {


                $text = $h->textContent;
                // check/filter stopwords and uniqueness
                // do so with other weights as well, basically narrow it down before counting
                $weighted_ft['0'] .= " " . $text;


        }
        // relevance wieght 5
        $includes = $doc->getElementsByTagName('h2');
        foreach ($includes as $h) {
            $weighted_ft['5'] .= " " . $h->textContent;
        }
        // relevance wieght 15
        $includes = $doc->getElementsByTagName('p');
        foreach ($includes as $p) {
            $weighted_ft['15'] .= " " . $p->textContent;
        }
            // pseudo; start counting frequencies and stuff
            // foreach weighted_ft sz do 
            //   foreach word in sz do 
            //      freqency / prominence
 }

    function html_entity_decode($toEncoding) {
        $encoding = mb_detect_encoding($this->body, "ASCII,JIS,UTF-8,ISO-8859-1,ISO-8859-15,EUC-JP,SJIS");
        $body = mb_convert_encoding($this->body, $toEncoding, ($encoding != "" ? $encoding : "auto"));
        return html_entity_decode($body, ENT_QUOTES, $toEncoding);
    }

Выше приведен класс, похожий на вашу базу данных, в которой загружено поле "тело страницы" заранее.

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

Примечание по полнотекстовой индексации:

При работе с небольшим количеством документов полнотекстовая поисковая система может напрямую сканировать содержимое документов с каждым запросом, стратегия называется последовательной сканирующий. Это то, что делают некоторые элементарные инструменты, такие как grep, при поиске.

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

После помещения в базу данных столбцы должны быть похожи на это, поэтому схема могло бы быть так, где мы сохраняли бы веса - и все равно предлагали бы сверхбыстрый метод запроса

CREATE TABLE IF NOT EXISTS `oo_pages` (
  `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `body` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'PageBody entity encoded html',
  `title` varchar(31) COLLATE utf8_danish_ci NOT NULL,
  `ft_index5` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted highest',
  `ft_index10` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted medium',
  `ft_index15` mediumtext COLLATE utf8_danish_ci NOT NULL COMMENT 'Regenerated cron-wise, weighted lesser',
  `ft_lastmodified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'last cron run',
  PRIMARY KEY (`id`),
  UNIQUE KEY `alias` (`alias`),
  FULLTEXT KEY `ft_index5` (`ft_index5`),
  FULLTEXT KEY `ft_index10` (`ft_index10`),
  FULLTEXT KEY `ft_index15` (`ft_index15`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_danish_ci;

Можно добавить индекс следующим образом:

ALTER TABLE `oo_pages` ADD FULLTEXT (
`named_column`
)

Особенность определения языка и последующего выбора базы данных стоп-слов с этого момента - это функция, которую я сам упустил, но она отличная - И По Книге! Так что спасибо за ваши усилия и этот ответ:)

Кроме того, имейте в виду, что есть не только тег заголовка, но и атрибуты заголовка anchor/img. Если по какой-то причине ваш аналитика переходит в паукообразное состояние, я бы предложил объединить ссылочную ссылку (<a>) заголовок и Текстовый контент с целевой страницей <title>

 4
Author: mschr, 2017-05-23 11:54:30

Я бы рекомендовал вместо того, чтобы заново изобретать колесо, использовать Apache SoIr для поиска и анализа. В нем есть почти все, что вам может понадобиться, в том числе обнаружение стоп-слов для более чем 30 языков [насколько я помню, может быть даже больше], и вы можете делать массу вещей с хранящимися в нем данными.

 2
Author: Shahriyar Imanov, 2012-05-31 13:09:12