2013-02-28 115 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