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:

正如您所写,您的表非常相似,因此您也许可以使用列聚合继承。通过这种方式,所有数据都存储在一个表中,因此您可以一起查询它们,并可以根据需要进行排序和分页。

于 2012-07-31T21:41:33.907 回答