Самая быстрая стандартная программа PHP для распознавания слов

Каков самый быстрый путь в PHP, чтобы взять список ключевого слова и соответствовать ему к результату поиска (как массив заголовков) для всех слов?

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

  • Получите некоторый действительно Большой кожаный ботинок
  • Кожаная обувь является большой
  • Великий день! Это - некоторый прохладный кожаный ботинок!
  • Обувь, сделанная из кожи, может быть большой

... в то время как они не были бы соответствием:

  • Кожаная обувь в продаже сегодня!
  • Вы будете любить эту кожаную обувь значительно
  • Большая обувь не обходится дешево

Я предполагаю, что существует некоторый прием с функциями массива или RegEx (Регулярное выражение) для достижения этого быстро.

5
задан Alan Moore 14 April 2010 в 01:54
поделиться

6 ответов

Я бы использовал индекс для слов в заголовках и проверял, есть ли все поисковые запросы в этом индексе:

$terms = explode(' ', 'great leather shoes');
$titles = array(
    'Get Some Really Great Leather Shoes',
    'Leather Shoes Are Great',
    'Great Day! Those Are Some Cool Leather Shoes!',
    'Shoes, Made of Leather, Can Be Great'
);
foreach ($titles as $title) {
    // extract words in lowercase and use them as key for the word index
    $wordIndex = array_flip(preg_split('/\P{L}+/u', mb_strtolower($title), -1, PREG_SPLIT_NO_EMPTY));
    // look up if every search term is in the index
    foreach ($terms as $term) {
        if (!isset($wordIndex[$term])) {
            // if one is missing, continue with the outer foreach
            continue 2;
        }
    }
    // echo matched title
    echo "match: $title";
}
4
ответ дан 13 December 2019 в 05:32
поделиться

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

if (in_array('great', $list) && in_array('leather', $list) && in_array('shoes', $list)) {
    // Do something
}
1
ответ дан 13 December 2019 в 05:32
поделиться

вы можете preg_grep () ваш массив против чего-то вроде

 /^(?=.*?\bgreat)(?=.*?\bleather)(?=.*?\shoes)/

или (возможно быстрее) grep каждое слово отдельно, а затем array_intersect результатов

{{ 1}}
3
ответ дан 13 December 2019 в 05:32
поделиться

Не знаю, как насчет абсолютного самого быстрого способа, но это, вероятно, самый быстрый способ сделать это с помощью regex:

'#(?:\b(?>great\b()|leather\b()|shoes\b()|\w++\b)\W*+)++\1\2\3#i'

Это соответствует каждому слову в строке, и если это слово оказывается одним из ваших ключевых слов, пустая группа захвата "проверяет его". После того, как все слова в строке найдены, обратные ссылки (\1\2\3) гарантируют, что каждое из трех ключевых слов было встречено хотя бы один раз.

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

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

1
ответ дан 13 December 2019 в 05:32
поделиться

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

$keywords = array(
    'great',
    'leather',
    'shoes'
);

$titles = array(
    'Get Some Really Great Leather Shoes',
    'Leather Shoes Are Great',
    'Great Day! Those Are Some Cool Leather Shoes!',
    'Shoes, Made of Leather, Can Be Great',
    'Leather Shoes on Sale Today!',
    'You\'ll Love These Leather Shoes Greatly',
    'Great Shoes Don\'t Come Cheap'
);

$matches = array();
foreach( $titles as $title )
{
  $wordsInTitle = preg_split( '~\b(\W+\b)?~', $title, null, PREG_SPLIT_NO_EMPTY );
  if( array_uintersect( $keywords, $wordsInTitle, 'strcasecmp' ) == $keywords )
  {
    // we have a match
    $matches[] = $title;
  }
}

var_dump( $matches );

Хотя я не знаю, как это оценивается.

2
ответ дан 13 December 2019 в 05:32
поделиться

Вы можете использовать

/(?=.*?\great\b)(?=.*?\bshoes\b)(?=.*?\bleather\b)/

Обратите внимание на пару вещей

a) Вам нужны границы слов на обоих концах, иначе вы можете найти слова, содержащие те, которые вы ищете, например, «кожаные туфли приносят величие».

б) Я использую ленивое сопоставление с подстановочными знаками (например, *?). Это повышает эффективность, поскольку по умолчанию * является жадным (т. Е. Потребляет столько символов, сколько может совпадать, и отказывается от них только в пользу общего совпадения). Так что, если у нас нет конечного?,. * Будет соответствовать всему в строке, а затем вернуться к поиску «отлично». Затем такая же процедура повторяется для «обуви» и «кожи». Делая * ленивым, мы избегаем этих ненужных возвратов.

1
ответ дан 13 December 2019 в 05:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: