2013-02-28 156 views
0

在我的网站上我有天主教百科全书。它有超过11000篇文章。用链接替换单词

我有兴趣用我的网站上的文章替换单词和短语,并链接到天主教百科全书中的相关条目。所以,如果有人说:

圣彼得是第一位教皇。

它应该用圣伯多禄文章的链接取代圣伯多禄,教皇与教皇文章的链接。

我有它的工作,但它非常缓慢。有超过30,000个可能的替代品,所以优化是非常重要的。我只是不确定该从哪里出发。

这是我现有的代码。请注意,它使用Drupal。而且,它会用[cathenlink]标签替换单词,并且该代码稍后会在代码中由真正的HTML链接替换。

function ce_execute_filter($text) 
{ 

    // If text is empty, return as-is 
    if (!$text) { 
     return $text; 
    } 

    // Split by paragraph 
    $lines = preg_split('/\n+/', $text, -1, PREG_SPLIT_DELIM_CAPTURE); 

    // Contains the parsed and linked text 
    $linked_text = ''; 

    foreach ($lines as $line) 
    { 

     // If this fragment is only one or more newline characters, 
     // Add it to $linked_text and continue without parsing 
     if (preg_match('/^\n+$/', $line)) { 
      $linked_text .= $line; 
      continue; 
     } 

     // Select any terms that might be in this line 
     // Ordered by descending length of term, 
     // so that the longest terms get replaced first 
     $result = db_query('SELECT title, term FROM {catholic_encyclopedia_terms} ' . 
       "WHERE :text LIKE CONCAT('%', CONCAT(term, '%')) " . 
       'GROUP BY term ' . 
       'ORDER BY char_length(term) DESC', 
       array(
        ':text' => $line 
        )) 
      ->fetchAll(); 

     // Array with lowercase term as key, title of entry as value 
     $terms = array(); 

     // Array of the terms only in descending order of length 
     $ordered_terms = array(); 

     foreach ($result as $r) 
     { 
      $terms[strtolower($r->term)] = $r->title; 
      $ordered_terms[] = preg_quote($r->term); 
     } 

     // If no terms were returned, add the line and continue without parsing. 
     if (empty($ordered_terms)) { 
      $linked_text .= $line; 
      continue; 
     } 

     // Do the replace 
     // Get the regexp by joining $ordered_terms with | 
     $line = preg_replace_callback('/\b('. 
        implode('|', $ordered_terms) . 
        ')\b/i', function ($matches) use($terms) 
       { 
       if ($matches[1]) { 
       return "[cathenlink=" . 
       $terms[strtolower($matches[1])] . "]" . 
       $matches[1] . "[/cathenlink]"; 
       } 
       }, 
       $line); 

     $linked_text .= $line; 
    } 

    return $linked_text; 
} 

我正在做这样的preg_replace,以便它不会替换一个单词两次。我会用strtr,但是没有办法确保它是一个完整的单词,而不仅仅是一个单词的一部分。

有什么办法可以让这个更快吗?现在它很慢。

回答

0

我认为LIKE这个关键字会让你放慢速度。它是indexed

你可以找到一些线索here

+0

谢谢。那么,我必须使用像**或类似的东西来缩小结果,否则它会更慢,因为它将返回所有30,000个以上的项。 – devbanana 2013-02-28 02:19:41

+0

它应该是'%whatever%'?,你可以使用'%whatever'单独优化它。 – 2013-02-28 02:22:43

+0

是的,它必须是%term%,因为否则该术语必须位于给定文本的开头或结尾,因此不起作用。 – devbanana 2013-02-28 02:31:43

0

你可以使用一个索引系统,如Lucene来索引天主教百科全书。我不怀疑它经常改变,所以索引可以在每日低音提琴上更新。 Lucene是用Java编写的,但我知道Zend有一个可以读取索引的PHP模块。

0

好吧,我认为我这样做的方式可能是最有效的。我想出的结果是将结果缓存一周,以便帖子不必每周解析超过一次。实施这个解决方案后,我看到我的网站在速度方面有了明显的改善,所以它似乎在工作。

+0

您也可以使用JavaScript AJAX调用回放到服务器上的特定功能来进行一些替换。这样,如果你想更新任何这些替换它会自动工作。将你的单词替换/链接信息保存到一个表中,然后在AJAX响应中将它们返回以将其替换到页面上。 – pthurmond 2013-02-28 21:10:19