您在這裡

Drupal自帶搜索改為Views關鍵詞過濾

James Qi 在 2017年11月23日 - 17:29 發表

  用Drupal很多年一直都是用的自帶搜索,但存在數據量大時速度很慢、搜索結果不準确等問題,中途嘗試過Apache Solr,但感覺太複雜、麻煩了。也知道Views可以用作内部搜索,但一直沒有實施。

  最近在設法降低MySQL服務器負載時,查看RDS後台的慢查詢日志,發現有相當多的慢查詢都是Drupal自帶的搜索造成的,特别是數據量大的中文站、搜索漢字詞特别長的時候。還有些數據量大的站,生成搜索索引都需要非常長的時間(生成的搜索表可能比内容類型的字段表大得多),自己去試着搜索也是非常慢(有些需要幾十秒以上,幾乎無法正常使用)。于是就嘗試用Views來替代,現在記錄如下:

  Views是可以帶參數來列表的,一種是使用Advanced設置裡面的CONTEXTUAL FILTERS,但這一般是用于關鍵詞是完整參數的情況,另一種使用FILTER CRITERIA來設置,可以選擇Global: Combine fields filter,在需要的字段組合中查找,一般采用Contains all words查詢,這就保持了足夠的靈活性,我們現在就是使用的這種辦法。截圖示範如下:

 

  上面這個Views的訪問URL就是這樣的形式:https://www.example.com/search-views?keyword=關+鍵+詞+Keyword

  替換系統自帶的搜索框需要自己做一個自定義搜索表單的Block,可以單個站設置,系列網站也可以在自定義模塊中設置,示例代碼如下:

function my_module_block_info() {
    $blocks=array();
    $blocks['search_form_for_web']=array(
        'info'=> t('Search').' '.t('Form').' '.t('For').' '.t('WEB'),
        'cache'=>DRUPAL_NO_CACHE,
        'weight'=>0,
        'status'=>1,
        'region'=>'header',
        'visibility'=>BLOCK_VISIBILITY_NOTLISTED,
        'pages'=>'',
    );

function my_module_block_view($delta = '') {
    $block=array();
    switch($delta){
        case 'search_form_for_web':
            $block['subject'] = '';
            if(user_access('access content')){      
                $button = t('Search');
                $placeholder = t('Keywords');
                global $language_url;
                global $base_url;
                $prefix_url = $language_url->prefix;
                $path = ($prefix_url == '') ? "" : "/$prefix_url";
                $output = "<form action=\"$base_url$path/search_redirect_web\" method=\"get\">
                    <input type=\"text\" name=\"keyword\" placeholder=\"$placeholder\" class=\"search_form\">
                    <input type=\"submit\" value=\"$button\" class=\"search_form\">
                    </form>";
                $block['content']=$output;
            }
        break;
        default:
    }
    return $block;
}

  可以看到這是獲取用戶填寫的搜索關鍵詞keyword後用get的方式提交到search_redirect_web這個重定向頁面,之所以要有一個重定向頁面是為了對keyword進行适當的轉換處理後再提交到Views裡去獲取結果。

  這個重定向頁面在自定義模塊中的定義示例如下:

function my_module_menu() {
  $items= array();

  $items['search_redirect_web'] = array (
    'title'=>'search redirect web',
    'page callback'=>'search_redirect_web',
    'access arguments'=>array('access content'),
  );
  
  return $items;
}

function search_redirect_web() {
    $request_uri = $_SERVER['REQUEST_URI'];
    $query_string = $_SERVER['QUERY_STRING'];
    $keyword = substr($query_string,strpos($query_string,'keyword=')+strlen('keyword='));
    if ($keyword != NULL) {
        $input = urldecode($keyword);
        $output_encode = keyword_convert($input);
        print "input = $input, output_encode = $output_encode, ";
        global $language_url;
        global $base_url;
        $prefix_url = $language_url->prefix;
        $path = ($prefix_url == '') ? "" : "/$prefix_url";
        $http_referer = $_SERVER['HTTP_REFERER'];
        if (strpos($http_referer,'?amp') != FALSE || strpos($http_referer,'&amp') != FALSE) {
            $amp_mip = '&amp';
        } elseif (strpos($http_referer,'?mip') != FALSE || strpos($http_referer,'&mip') != FALSE) {
            $amp_mip = '&mip';
        } else {
            $amp_mip = '';
        }
        $url = "$base_url$path/search-views?keyword=$output_encode$amp_mip";
        print "url = $url";
        header("location: $url");
    } else {
        print "not redirect, request_uri = $request_uri, query_string = $query_string\n";
    }
}

function keyword_convert($input) {
    $input_length = mb_strlen($input);
    $output = '';
    $remain = $input;
    for ($i=0; $i<$input_length; $i++) {
        $sub = substr($remain,0,1);
        $mb_sub = mb_substr($remain,0,1);
        if ($sub == $mb_sub) {
            $output .= $sub;
        } else {
            $output .= " $mb_sub ";
        }
        $remain = mb_substr($remain, 1);
        print "i = $i, sub = $sub, mb_sub = $mb_sub, output = $output, remain = $remain<br />\n";
    }
    $output = str_replace('  ',' ',$output);
    $output = trim($output);
    $output_encode = urlencode($output);
    $output_encode = str_replace('+++','+',$output_encode);
    $output_encode = str_replace('++','+',$output_encode);
    $output_encode = str_replace('++','+',$output_encode);
    return $output_encode;
}

  這裡的keyword_convert轉換函數就是對輸入的關鍵詞進行處理,然後編碼成網址形式輸出。因為需要考慮多語言、多站點路徑、amp/mip版本的兼容,上面寫得複雜了一點,如果不需要考慮這麼多,還可以簡化。

  總結一下,就是需要三個東西:

  1. 一個Block用于接收用戶輸入關鍵詞(簡單的時候就用輸入一個字段關鍵詞,複雜也可以輸入多個字段關鍵詞);
  2. 一個重定向頁面,用于處理用戶輸入的關鍵詞(中文分詞、判斷直接跳轉、限制長度、去掉無意義符号等);
  3. 一個Views,用于查詢及返回結果(簡單的時候采用字段過濾,複雜也可以采用多個字段過濾或者選擇)。

  Drupal自帶的搜索隻适合中小網站,像是一個黑盒,不需要很了解其原理,能夠使用就行,簡單易行。但對于數據量大、用戶要求精準的情況,還是采用Views的方式合适,可以定制搜索的結果範圍,合理限制搜索負載,快速給出結果,隻是實現起來複雜一些。

自由标簽:

發表新回應

Plain text

  • 不允許使用 HTML 標籤。
  • 自動將網址與電子郵件地址轉變為連結。
  • 自動斷行和分段。