web-dev-qa-db-ja.com

検索クエリでのLIKEの使用

ユーザーが検索を実行したときにキーワードが含まれている単語を検索したいと思います。 hook_query_alter()にフックしようとしました:

_function MYMODULE_query_alter(&$query) {
  // Check if this is a search query   
  if (!$query->hasTag('search_node')) {
    return;
  }

  $conditions = &$query->conditions();
  $conditions = &$conditions[1]['field']->conditions();
  // Change the condition to '%<keyword>%'
  // and add LIKE as operator
  $conditions[0]['value'] = "%" . $conditions[0]['value'] . "%";
  $conditions[0]['operator'] = 'LIKE';
}
_

検索クエリを変更できますが、結果が得られません。

実行される変更されたクエリは次のようになります。

_SELECT FROM {search_index} i
  INNER JOIN {node} n ON n.nid = i.sid
  INNER JOIN {search_total} t ON i.Word = t.Word
  WHERE (n.status = :db_condition_placeholder_0)
    AND ((i.Word LIKE :db_condition_placeholder_1 ESCAPE '\\'))
    AND (i.type = :db_condition_placeholder_2) 
  GROUP BY i.type, i.sid
  HAVING  (COUNT(*) >= :matches)
_

また、SelectQueryオブジェクトのプレースホルダーは次のように設定されています。

_[:db_condition_placeholder_0] => 1
[:db_condition_placeholder_1] => %liv%
[:db_condition_placeholder_2] => node
_

テーブル_search_index_と_search_total_の両方にlivを含む2、3の単語が含まれていることを確認できるため、結果が返されるはずです。

ファジー検索 モジュールも試しましたが、提供された検索を通常の検索フォームに接続する方法がわかりません。

db_like()を試しましたが、成功していません。

_=_条件ではなくLIKEを使用してインデックスを検索するようにデフォルトの検索を変更することがそれほど難しいのはなぜですか?

私がそれを実装する方法を知っているだけなら、このようなものはうまくいくはずです:

_$keyword = $_GET['s'];
$status = 1;
$types = array('article', 'contact');

db_query("SELECT node.nid FROM {node} n
  INNER JOIN {search_index} si 
    ON si.sid = n.nid 
    AND si.Word LIKE :keyword
  INNER JOIN {search_dataset} sd ON sd.sid = n.nid
  WHERE n.status = :status AND n.type IN (:types)
  GROUP BY n.nid", array(
    ':keyword' => '%' . db_like($keyword) . '%',
    ':status' => $status,
    ':types' => $types
  )
);
_
5
Cyclonecode

SearchQuery::parseSearchExpression() がそれを実行するため、変更したクエリでは結果が得られません。具体的には、300行目あたり:

// Single ANDed term.
else {
  ...
  $this->conditions->condition('d.data', "% $key %", 'LIKE');
  ...
}

条件のスペースに注意してください。

結果を取得するには、これらのスペースをクエリから削除する必要がありますが、これは簡単な作業ではありません。私はこのようなものが必要になると信じています:

function my_module_query_alter($query) {
  if ($query->hasTag('search_node')) {
    $conditions = &$query->conditions();
    $conditions = &$conditions[1]['field']->conditions();
    $conditions[0]['value'] = '%' . $conditions[0]['value'] . '%';
    $conditions[0]['operator'] = 'LIKE';
  }

  if ($query instanceof PagerDefault) {
    PagerDefaultHelper::alter($query);
  }
}

class PagerDefaultHelper extends PagerDefault {
  public static function alter(PagerDefault &$query) {
    $search_query = &$query->query;
    SearchQueryHelper::alter($search_query);
  }
}

class SearchQueryHelper extends SearchQuery {
  public static function alter(SearchQuery &$query) {
    $conditions = &$query->conditions->conditions();
    $conditions[0]['value'] = str_replace(' ', '', $conditions[0]['value']);
  }
}

ただし、これは単一の単語を検索する場合にのみ機能します。複数の単語、ORされた単語、または除外された単語を使用する検索では、このアプローチを構築する必要があります。

1
morbiD

search api pages モジュール(またはビュー)を介してファジー検索を接続します。

ビューを使用する場合は、ビューの検索ブロックを目的の領域に配置できます。

手動による説明:(あいまい検索から)

  • メインのSearch API構成ページから、Fuzzy Searchサービスクラスを使用してサーバーを作成します。
  • 作成したサーバーを使用してインデックスを作成します。
  • [ワークフロー]タブをクリックします。
  • 「完全なエンティティビュー」を有効にします。
  • 次のプロセッサを有効にします:両方のファジー検索プロセッサ、大文字と小文字を区別しない、HTMLフィルタ、およびトークナイザ。
  • あいまい検索抜粋プロセッサをリストの一番下に移動し、そのすぐ上にあるあいまい検索検索設定プロセッサを移動します。
  • デフォルト設定で問題ありません。
  • サイトを検索する場所を提供するには、Search API Pagesモジュールまたはビューが必要です。
  • メインのSearch APIページに移動します。
  • [検索ページ]をクリックして検索ページを追加し、上記で作成したインデックス、クエリタイプの複数の用語、検索結果としてテーマを設定した表示モードを構成します。
  • ビューの場合、デフォルトのfuzzyseachインデックスを使用して新しいビューを作成し、ページ表示を追加して、必要に応じて構成します。
  • Cronを実行してコンテンツのインデックスを作成します。検索ページのパスにアクセスします。
1
rémy

db_like を使用してdb_like($ prefix)を追加すると、うまくいくと思います!

(i.Word LIKE :db_condition_placeholder_1 ESCAPE '\\')

Convert into:

 condition('i.Word', db_like($prefix) . '%', 'LIKE')

私はカスタマイズの専門家ではありませんが、あなたに役立つかもしれません!

0
Adi

これがこの問題を解決する最良の方法であるかどうかはわかりませんが、結局 hook_node_update_index() を使用して、単語の一部の検索をサポートしました。

function hook_node_update_index($node)
{
   $result = '';

   // how long should each part be?
   $options = array(3, 4, 5);

   // only look at the body and title
   $content = $node->body['und'][0]['value'] . ' ' . $node->title;
   $content = strip_tags($content);
   $content = drupal_strtolower($content);

   $words = explode(' ', $content);

   $parts = array();

   // split words into parts
   foreach ($words as $Word) {
     // if the length is less than the size we would like to split at
     // then there's no need to continue
     $length = drupal_strlen($Word);

     foreach ($options as $option) {
        if ($length < $option) {
           $result .= ' ' . $Word;
           break;
        }
        for ($i=0; $i < ($length - $option + 1); $i++) {
           $parts[] = drupal_substr($Word, $i, $option);
        }     
     }
   }

   // append all created parts for the words
   if(count($parts)) {
      $result .= ' ' . implode(' ', $parts);
   }

   return $result;
}

ドキュメントから:

関数hook_node_update_index

検索用にインデックス付けされているノードを操作します。

このフックは、node_load()の後、およびnode_view()の結果が$ node-> renderedとしてノードオブジェクトに追加された後に、検索インデックスの作成中に呼び出されます。

これは将来の誰かを助けるかもしれないので、私はこれを答えとして追加します。各キーワードにLIKE条件を使用するより良いソリューションを探しています。

0
Cyclonecode