Индексирование связанных объектов с помощью Zend Lucene

Я настроил поиск в своем приложении, но хочу расширить его до свойств индекса, связанных "один ко многим". Например, человек может иметь много имен пользователей, поэтому они должны храниться отдельно, как в следующем примере:

person:
  id:         ~
  name:       {type: varchar(100), required: true}

username:
  person_id:  {type: integer, foreignTable: person, foreignReference: id}
  username:   {type: varchar(20), primaryKey: true, required: true}

До сих пор я следовал примеру Jobeet, чтобы использовать Zend Lucene в своем приложении, и я могу искать свойства name в Person, такие как Name.

Я не мог найти способ сделать это автоматически через Symfony или Lucene, поэтому я попытался добавить элементы в индекс Person следующим образом:

foreach ($this->getUsernames() as $i => $username)
{
  $doc->addField(Zend_Search_Lucene_Field::Text('username' . $i,
      $username->getUsername(), 'utf-8'));
}

Затем я попытался обновить этот индекс при добавлении нового имени пользователя, обновив функцию сохранения имени пользователя:

public function save(PropelPDO $con = null)
{
  $ret = parent::save($con);

  // reindex the person
  $person = $this->getPerson();
  $person->save();

  return $ret;
}

Это прекрасно работает, пока человек создается во время выполнения, но если он загружен из приборов, getUsernames() ничего не возвращает. Код выполняется дважды (один раз при загрузке Person и один раз при добавлении имени пользователя). Есть ли причина для этого? Могу ли я обойти это как-нибудь?

Другой способ сделать это также будет оценен. Похоже, что Lucene может выполнять поиск по нескольким индексам, используя класс Zend_Lucene_Search_Interface_MultiSearcher, как описано в этом вопросе. Тем не менее, я не могу заставить это работать.

Я нашел подобный вопрос здесь, но не нашел указателей.

Я сейчас использую Propel 1.6.

1 ответ

Вы не указали, какую версию Propel вы используете. Видя, что вы используете PDO, вы, скорее всего, используете 1,3+.

если имя объекта правильно инициализировано, то есть:

<?php
$username = new Username();
$username->setUsername('foobar');
$username->setPerson($person);

Вызов $username->save(); должен также вызывать save () для $person, а также объект $ person должен содержать объект Username.

Но что касается инициализации $person, здесь есть "особенность". (некоторые могут назвать это ошибкой..)

Если вы инициализируете $ person как:

$person = PersonPeer::retrieveByPk(123);
//or for 1.5+
$person = PersonQuery::create()->findPk(123);

список имен $ person будет пуст. И когда вы звоните

 $username->setPerson($person);

$ username будет добавлен в список имен $person, что, в свою очередь, означает, что вызов $person->getUsernames() не будет автоматически извлекать имена пользователей из db, так как список уже не пуст.

Поэтому вам нужно инициализировать $ person с именами пользователей. Либо как

<?php
$person = PersonQuery::create()->joinWith('Person.Usernames')->filterById(123)->findOne();

или же

<?php
$person = PersonPeer::retrieveByPk(123);
$person->getUsernames(); //trigger list fetch
Другие вопросы по тегам