2

私は Symfony プロジェクトを持っており、Zend Lucene 検索フレームワークを使用してサイトの検索を統合しました。美しく機能しますが、1 つのテーブルの検索に限定されます。

ユーザーがサイト全体 (8 つの選択テーブル) を検索し、結果をまとめて返すことができるようにする必要があります。各テーブルには、インデックスが作成された同じフィールドがあります。これは、テーブルを指定してクエリを呼び出すコードです。

結果を得るために 8 つのテーブルすべてを調べる方法はありますか?

public function getForLuceneQuery($query)
{
  $hits = self::getLuceneIndex()->find($query);

  $pks = array();
  foreach ($hits as $hit)
  {
    $pks[] = $hit->pk;
  }

  if (empty($pks))
  {
    return array();
  }
  $alltables = Doctrine_Core::getTable('Car');
  $q = $alltables->createQuery('j')
     ->whereIn('j.token', $pks)
     ->orderBy('j.endtime ASC')
     ->andwhere('j.endtime > ?', date('Y-m-d H:i:s', time()))
     ->andWhere('j.activated = ?', '1')
     ->limit(21);

  return $q->execute();
}

8 つのテーブルの背景を少し説明すると、それらはすべて基本的に似ています。それらにはすべてタイトル、メーカー、モデルなどがあるため、それらすべてに対して単一のクエリを実行し、すべての結果を昇順で返す必要があります (テーブルに関係なく)。Doctrine_core::getTable コマンドは、複数のテーブルや配列を好まないようです (正しく実行していない限り)。ありがとう!

更新 (作業中):

これが更新されたコードです。これは私がSearchTable.class.phpファイルに持っているものです:

public function getForLuceneQuery($query)
{
  // sort search result by end time
  $hits = self::getLuceneIndex()->find(
    $query, 'endtime', SORT_NUMERIC, SORT_ASC
  );

  $result = array(
    'index' => $hits,
    'database' => array(),
  );

  // group search result by class
  foreach ($hits as $hit)
  {
    if (!isset($result['database'][$hit->class]))
    {
      $result['database'][$hit->class] = array();
    }

    $result['database'][$hit->class][] = $hit->pk;
  }

  // replace primary keys with real results
  foreach ($result['database'] as $class => $pks)
  {
    $result['database'][$class] = Doctrine_Query::create()
      // important to INDEXBY the same field as $hit->pk
      ->from($class . ' j INDEXBY j.token')
      ->whereIn('j.token', $pks)
      ->orderBy('j.endtime ASC')
      ->andwhere('j.endtime > ?', date('Y-m-d H:i:s', time()))
      ->andWhere('j.activated = ?', '1')
      ->limit(21)
      ->execute();

  }

  return $result;
}

actions.class.php検索モジュールのファイルにあるものは次のとおりです。

public function executeIndex(sfWebRequest $request)
  {
    $this->forwardUnless($query = $request->getParameter('query'), 'home', 'index');

    $this->results = Doctrine_Core::getTable('Search') 
      ->getForLuceneQuery($query);

  }

そして最後に、これは私のテンプレート ファイルですindexSuccess.php 。理解しやすいように簡略化しています。私のindexSuccess.phpはもっと複雑ですが、値を呼び出すことができるようになったので、さらにカスタマイズできます。

  <div class="product_list"
  <ul>
    <?php foreach ($results['index'] as $hit): ?>
      <li class="item">
      <?php if (isset($results['database'][$hit->class][$hit->pk])) ?>
        <span class="title">
            <?php echo $results['database'][$hit->class][$hit->pk]->getTitle() ?>
        </span>
      </li>
    <?php endforeach ?>
  </ul>
  </div>

これは美しく機能します。検索結果の各フィールドを呼び出すことでカスタマイズでき、完璧に機能します。各テーブルに同じタイトルのアイテムを追加すると、検索結果にすべてが表示されました。どうもありがとう!

4

1 に答える 1

2

わかった。コードを使用して、ヒントを提供しようとします:)

まず、これらのフィールドをインデックスに追加する必要があります。

$doc->addField(Zend_Search_Lucene_Field::Keyword('class', get_class($record)));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('endtime', strtotime($record->get('endtime'))));

これらの新しいフィールドを使用する必要があります。

public function getForLuceneQuery($query)
{
  // sort search result by end time
  $hits = self::getLuceneIndex()->find(
    $query, 'endtime', SORT_NUMERIC, SORT_ASC
  );

  $result = array(
    'index' => $hits,
    'database' => array(),
  );

  // group search result by class
  foreach ($hits as $hit)
  {
    if (!isset($result['database'][$hit->class]))
    {
      $result['database'][$hit->class] = array();
    }

    $result['database'][$hit->class][] = $hit->pk;
  }

  // replace primary keys with real results
  foreach ($result['database'] as $class => $pks)
  {
    $result['database'][$class] = Doctrine_Query::create()
      // important to INDEXBY the same field as $hit->pk
      ->from($class . ' j INDEXBY j.token')
      ->whereIn('j.token', $pks)
      ->orderBy('j.endtime ASC')
      ->andwhere('j.endtime > ?', date('Y-m-d H:i:s', time()))
      ->andWhere('j.activated = ?', '1')
      ->limit(21)
      ->execute();

    // if you want different query per table
    // you should call a function which executes the query
    //
    // if (!method_exists($table = Doctrine_Core::getTable($class), 'getLuceneSearchResult'))
    // {
    //   throw new RuntimeException(sprintf('"%s::%s" have to be exists to get the search results.', get_class($table), 'getLuceneSearchResult'));
    // }
    //
    // $results[$class] = call_user_func(array($table, 'getLuceneSearchResult'), $pks);
  }

  return $result;
}

その後、テンプレートで反復処理を$result['index']行い、結果を表示する必要があります$result['database']

foreach ($result['index'] as $hit)
{
  if (isset($result['database'][$hit->class][$hit->pk]))
  {
    echo $result['database'][$hit->class][$hit->pk];
  }
}

そして、私が考えることができる同じ代替(おそらくより良い)ソリューションがあります:

代替ソリューション #1:

インデックスにデータを保存すると、このデータに検索結果でアクセスできるようになります。結果を表示するときにあまり多くのデータを必要とせず、インデックスを頻繁に更新できる場合、これは良いオプションだと思います。このようにして、ページネーションを使用でき、SQL クエリはまったく必要ありません。

$doc->addField(Zend_Search_Lucene_Field::Text('title', $content->get('title')));
...
$hit->title;

代替ソリューション #2:

あなたが書いたように、あなたのテーブルは非常に似ているので、おそらく列集計の継承を使用できます。このようにして、すべてのデータが 1 つのテーブルに格納されるため、それらをまとめてクエリし、必要に応じて順序付けやページ付けを行うことができます。

于 2012-07-31T21:41:33.907 に答える