Индексирование связанных объектов с помощью 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