Question

I am building an app that has a Calendar in which users can annotate events.

The Calendar is private to each user, that is, user A cannot see the events on user B's calendar.

I would like to index the calendar events using Zend Lucene, but I'm unsure how to do this.

I could have Lucene index all events together, regardless of user -- but then when a search is done it will show events of one user to the other, and that's not what I want.

I don't think it would be a good idea to create an index exclusive to each user, but am out of ideas how to:

  • create a common index of calendar events from all users
  • when a search is done, force results to show only events that belong to user performing the search

Any ideas/suggestions/pointers on how to do this?

Was it helpful?

Solution

Here's how I solved this issue:

First, make sure you include user_id field when building the index

Note that it is wise to use Keyword() for user_id since we want Lucene to search as well as display this data in results.

    $doc = new Zend_Search_Lucene_Document();

    $doc->addField(Zend_Search_Lucene_Field::Keyword('user_id', $row->user_id));
    $doc->addField(Zend_Search_Lucene_Field::UnIndexed('date_1', $row->date_1));
    $doc->addField(Zend_Search_Lucene_Field::Text('title', $row->title));

    $index->addDocument($doc);

     //etc

Next, add a boolean subquery on the backend (programatically) that will force all results to include the query string (user's search input) AND this user's user_id.

    $index = Zend_Search_Lucene::open($this->search_index);

    // add user's input to parser
    $query      = Zend_Search_Lucene_Search_QueryParser::parse($query_string);

    // add boolean query
    $query_bool = new Zend_Search_Lucene_Search_Query_Boolean();

    // add user id as a term
    // note this is saying that a specific `user_id`
    // must be found in a specific field (user_id)
    $user_id    = get_user_id(); // or use your own 'get user id' function 
    $term       = new Zend_Search_Lucene_Index_Term($user_id, 'user_id');
    $subquery1  = new Zend_Search_Lucene_Search_Query_Term($term);

    // construct boolean requiring both user id and string
    $query_bool->addSubquery($query, true);     // required
    $query_bool->addSubquery($subquery1, true); // required

    $query_result = $index->find($query_bool);

And there you have it.

Now if user 123 searches for 'appointment', Lucene will make the search actually be something like appointment AND user_id=123.

Let me know if there's any way to improve this - glad to discuss.

OTHER TIPS

I didn't try this, but probably it will work.

You can index ID in user_id field and search event that must have in 'user_id' field searched phrase, in your case the number:

$query = new Zend_Search_Lucene_Search_Query_Phrase(array('333'), null, 'user_id');
$hits1 = $index->find($query);

This will search for '333' phrase in a 'user_id' field.

I am not sure that this wouldn't return to you all index whit '333' number like '3334', '3335',... you have to try. If this return to you all other results(3334, 3335,...), you can set that you want to search only '333' but I leave it to your research :)

You can find all what you need here: Zend_Search


In any case, You can store user_id in your index. Than when someone search events you have to display only result that have:

user_id from index == user_id from session, this will work for sure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top