2013-02-28 8 views
0

내 사이트에는 카톨릭 백과 사전이 있습니다. 그것에는 11,000 이상의 기사가 있습니다.링크로 단어 바꾸기

내 사이트의 기사에있는 단어와 문구를 카톨릭 백과 사전의 관련 항목에 대한 링크로 바꾸는 데 관심이 있습니다. 따라서, 누군가가 말하는 경우 :

성 베드로는 첫 번째 교황이었습니다.

성 베드로가 성 베드로의 기사로 연결되는 링크로 바뀌어야하고, 교황 문서에 대한 링크가 있어야합니다.

나는 작동하지만 아주 느립니다. 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

+0

은'% whatever %'이어야합니까? '% whatever'만을 사용하여 최적화 할 수 있습니다. –

+0

예, % term %이어야합니다. 그렇지 않으면 용어가 주어진 텍스트의 처음이나 끝에 있어야하므로 작동하지 않습니다. – devbanana

0

당신은 인덱싱 시스템을 사용할 수를 찾을 수 있습니다. 자주 변경되지 않는다고 생각하지 않으므로 매일 bassis에서 인덱싱을 업데이트 할 수 있습니다. Lucene은 Java로 작성되었지만 Zend에는 색인을 읽을 수있는 PHP 모듈이 있습니다.

0

좋아, 내가하고있는 방식이 아마 가장 효율적이라고 생각한다. 내가 생각해 낸 것은 일주일에 한 번 결과를 캐싱하여 게시물을 일주일에 한 번 이상 파싱 할 필요가 없도록하는 것입니다. 이 솔루션을 구현하면 사이트 속도가 크게 향상되어 작동하는 것으로 보입니다.

+0

자바 스크립트 AJAX가 서버의 특정 기능으로 다시 호출되어 일부 교체 작업을 수행 할 수도 있습니다. 그렇게하면 해당 대체물을 업데이트하려는 경우 자동으로 작동합니다. 단어 교체/링크 정보를 테이블에 저장하고 AJAX 응답으로 반환하면 페이지에서 바꿀 수 있습니다. – pthurmond