Druckles
Druckles

Reputation: 3782

Indexing Related Entities Using Zend Lucene

I have set up search in my application, but wish to expand it to index properties related in a one-to-many way. For instance, a person can have many usernames, so they have to be kept separate, as in the following example:

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}

So far I have followed the Jobeet example to use Zend Lucene within my application, and I can search on properties of name within Person, such as Name.

I couldn't find any way to do this automatically through Symfony or Lucene, so I attempted to add the items in the Person's index like so:

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

I then attempted to update this index whenever a new Username is added by updating Username's save function:

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

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

  return $ret;
}

This works fine as long as the person is created at run-time, but if loaded from fixtures, getUsernames() returns nothing. The code is executed twice (once while loading Person, and once when adding the Username). Is there any reason for this? Can I get around this somehow?

Another way of doing this would also be appreciated. It appears that Lucene can search over multiple indices using the Zend_Lucene_Search_Interface_MultiSearcher class, as described in this question. However, I can't seem to get this working.

I found a similar question here, but found no pointers.

I am now using Propel 1.6.

Upvotes: 2

Views: 454

Answers (1)

NiklasN
NiklasN

Reputation: 559

You didn't specify which propel version you are using. Seeing you are using PDO, you most likely are using 1.3+.

if the Username object is initialized right, that is:

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

Calling $username->save(); should trigger also save() for the $person, and also the $person object should contain the Username object.

But what comes to the $person initialization, there is a "feature". (some might call it a bug..)

If you initialize $person like:

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

the $person's Usernames-list will be empty. And when you call

 $username->setPerson($person);

the $username will be added to the $person's Usernames-list, which in turn means calling $person->getUsernames() won't automatically fetch the usernames from db, as the list is already non-empty.

So you need to initialize $person with the usernames. Either like

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

or

<?php
$person = PersonPeer::retrieveByPk(123);
$person->getUsernames(); //trigger list fetch

Upvotes: 1

Related Questions