Searchable Plugin

mirrorChanges=true not working when updating objects via GORM

Details

  • Type: Bug Bug
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 0.6
  • Component/s: None
  • Labels:
    None
  • Environment:
    Grails 1.1, Searchable 0.5.3

Description

We have noticed in a couple of projects that objects updated via
GORM are not automatically reindexed. However, objects created
(save()) are reindexed.

In https://svn.codehaus.org/grails-plugins/grails-searchable/trunk/src/conf/Searchable.groovy,
the following is stated:

/**
    * Should changes made through GORM/Hibernate be mirrored to the index
    * automatically (using Compass::GPS)?
    *
    * If false, you must manage the index manually using index/unindex/reindex
    */
   mirrorChanges = true

But that doesn't work for us. We have to manually call domainObject.reindex()

A similar problem/workaround was posted to this list:

http://www.nabble.com/searchable-plugin%2C-missing-component-from-lucene-doc--td21067300.html

Issue Links

Activity

Hide
Malte Huebner added a comment -

Hi all, we have similar issues in searchable 0.5.4.

Show
Malte Huebner added a comment - Hi all, we have similar issues in searchable 0.5.4.
Hide
Maricel Quesada added a comment - - edited

I am currently having the exact same problem using 0.5.5. Reindexing works perfectly when saving but not when updating.

Also, something important I noticed is if I use objectDomain.reindex() when updating an object, the properties that are references don't get indexed, only the components.

Show
Maricel Quesada added a comment - - edited I am currently having the exact same problem using 0.5.5. Reindexing works perfectly when saving but not when updating. Also, something important I noticed is if I use objectDomain.reindex() when updating an object, the properties that are references don't get indexed, only the components.
Hide
Daniel Lees added a comment -

I have been experiencing the same issue using searchable 0.5.5. I have investigated the issue tracing through the source code and have found the issue to be in the following class/method.

class HibernateEventListenerUtils {

...

public static void persistPending(CompassSession session, Object entity, Map<Object, Collection> pendingMap, boolean create) {
for (Iterator iter = pendingMap.keySet().iterator(); iter.hasNext() {
Object pending = iter.next();
Collection dependencies = pendingMap.get(pending);
if (dependencies.remove(entity)) {
if (dependencies.isEmpty()) {
if (create) { session.create(pending); } else { session.save(pending); }
iter.remove();
}
}
}
}

...

}

From reading where this code is called from and the parameters passed it seems that the following line will never be true :-

if (dependencies.remove(entity))

this seems to be checking that the key from the map is in the values of the map for that key, this will never be the case resulting in the pending objects never being saved (lucene index).

Reading the original source i struggled to understand what it was trying to do, I thought it was trying to remove all the dependencies form the entity then save that entity but when i corrected the code to do this it resulted in a hibernate concurrent exception. I then changed it to just save each entity that was in the key of the map and this seemed to work, i checked and also the dependencies are also saved/updated in the lucene index. This works for me but i presume there is a reason for trying to remove the dependencies, otherwise the entity would just be saved in place in the HibernateEventListener. The updated method is shown below, please could you look at this and see if there are any issues that we haven't yet found.

public static void persistPending(CompassSession session, Object entity, Map<Object, Collection> pendingMap, boolean create) {
// Iterate around all the entities in the map and save/update them
for (Iterator iter = pendingMap.keySet().iterator(); iter.hasNext() {
Object pending = iter.next();
if (create) { session.create(pending); } else { session.save(pending); }
}
}

Thanks

Daniel Lees

Show
Daniel Lees added a comment - I have been experiencing the same issue using searchable 0.5.5. I have investigated the issue tracing through the source code and have found the issue to be in the following class/method. class HibernateEventListenerUtils { ... public static void persistPending(CompassSession session, Object entity, Map<Object, Collection> pendingMap, boolean create) { for (Iterator iter = pendingMap.keySet().iterator(); iter.hasNext() { Object pending = iter.next(); Collection dependencies = pendingMap.get(pending); if (dependencies.remove(entity)) { if (dependencies.isEmpty()) { if (create) { session.create(pending); } else { session.save(pending); } iter.remove(); } } } } ... } From reading where this code is called from and the parameters passed it seems that the following line will never be true :- if (dependencies.remove(entity)) this seems to be checking that the key from the map is in the values of the map for that key, this will never be the case resulting in the pending objects never being saved (lucene index). Reading the original source i struggled to understand what it was trying to do, I thought it was trying to remove all the dependencies form the entity then save that entity but when i corrected the code to do this it resulted in a hibernate concurrent exception. I then changed it to just save each entity that was in the key of the map and this seemed to work, i checked and also the dependencies are also saved/updated in the lucene index. This works for me but i presume there is a reason for trying to remove the dependencies, otherwise the entity would just be saved in place in the HibernateEventListener. The updated method is shown below, please could you look at this and see if there are any issues that we haven't yet found. public static void persistPending(CompassSession session, Object entity, Map<Object, Collection> pendingMap, boolean create) { // Iterate around all the entities in the map and save/update them for (Iterator iter = pendingMap.keySet().iterator(); iter.hasNext() { Object pending = iter.next(); if (create) { session.create(pending); } else { session.save(pending); } } } Thanks Daniel Lees
Hide
vu duc tung added a comment -

The patch of Daniel Lees works, naturly, still not extensive tested but it works.
I built it with Compass 2.1.4.

Show
vu duc tung added a comment - The patch of Daniel Lees works, naturly, still not extensive tested but it works. I built it with Compass 2.1.4.
Hide
Gianny DAMOUR added a comment -

Hi,

Using Compass 2.1.4 instead of 2.1.0 solves the problem as expected. It would be great to release a new version of searchable with 2.1.4.

Thanks,
Gianny

Show
Gianny DAMOUR added a comment - Hi, Using Compass 2.1.4 instead of 2.1.0 solves the problem as expected. It would be great to release a new version of searchable with 2.1.4. Thanks, Gianny
Hide
Peter Ledbrook added a comment -

This seems to be fixed in version 0.6-SNAPSHOT of the plugin (which uses a custom 2.2 version of Compass). Can someone please try it?

Show
Peter Ledbrook added a comment - This seems to be fixed in version 0.6-SNAPSHOT of the plugin (which uses a custom 2.2 version of Compass). Can someone please try it?
Hide
Gavin Kromhout added a comment -

0.6-SNAPSHOT causes the following error for me (Grails-1.3.5 even after a clean):

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compass': FactoryBean threw exception on object creation; nested exception is java.lang.NoSuchMethodError: org.compass.core.mapping.ResourceMapping.getSpellCheck()Lorg/compass/core/mapping/SpellCheck;
... 23 more
Caused by: java.lang.NoSuchMethodError: org.compass.core.mapping.ResourceMapping.getSpellCheck()Lorg/compass/core/mapping/SpellCheck;
... 23 more

However mirroring of the root object always worked for me, certainly in 0.5.5 and 0.5.5.1 it does (Grails-1.2.2 or Grails-1.3.5). Mirroring of cascading updates from searchable components not though see:
http://jira.codehaus.org/browse/GRAILSPLUGINS-2273

Show
Gavin Kromhout added a comment - 0.6-SNAPSHOT causes the following error for me (Grails-1.3.5 even after a clean): Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compass': FactoryBean threw exception on object creation; nested exception is java.lang.NoSuchMethodError: org.compass.core.mapping.ResourceMapping.getSpellCheck()Lorg/compass/core/mapping/SpellCheck; ... 23 more Caused by: java.lang.NoSuchMethodError: org.compass.core.mapping.ResourceMapping.getSpellCheck()Lorg/compass/core/mapping/SpellCheck; ... 23 more However mirroring of the root object always worked for me, certainly in 0.5.5 and 0.5.5.1 it does (Grails-1.2.2 or Grails-1.3.5). Mirroring of cascading updates from searchable components not though see: http://jira.codehaus.org/browse/GRAILSPLUGINS-2273
Hide
Peter Ledbrook added a comment -

Make sure you do a grails clean after installing the 0.6-SNAPSHOT. The above suggests you have classes compiled against the older Compass JAR.

Show
Peter Ledbrook added a comment - Make sure you do a grails clean after installing the 0.6-SNAPSHOT. The above suggests you have classes compiled against the older Compass JAR.
Hide
Peter Ledbrook added a comment -

OK, just saw you mentioned you tried a clean. Still, it appears an older version of Compass is still on the classpath of your application. You could try clearing the directory where the plugins are installed. By default ~/.grails/1.3.5/projects/<projName>/plugins.

Show
Peter Ledbrook added a comment - OK, just saw you mentioned you tried a clean. Still, it appears an older version of Compass is still on the classpath of your application. You could try clearing the directory where the plugins are installed. By default ~/.grails/1.3.5/projects/<projName>/plugins.
Hide
Peter Ledbrook added a comment -

Assuming fixed already or with the latest Compass and Lucene libraries.

Show
Peter Ledbrook added a comment - Assuming fixed already or with the latest Compass and Lucene libraries.
Hide
Gavin Kromhout added a comment -

Ah, I had set dependencies in BuildConfig to get around this and another problem.
That pretty much invalidates my comment about it working in previous versions, confirms Gianny DAMOUR's version comment and I can confirm that 0.6-SNAPSHOT is working for me in Grails-1.3.5.

My Grails-1.2.2 environment appears to run into a plugin conflict similar to this:
http://grails.1312388.n4.nabble.com/Plugin-Incompatibility-Multi-Tenant-Searchable-td1354534.html

BuildConfig.groovy code to run compass-2.1.4 in searchable-0.5.5:

grails.war.resources = { stagingDir, args ->
    // Included by searchable plugin.
    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0.jar"
    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0-src.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-core.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-analyzers.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-highlighter.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-queries.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-snowball.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-spellchecker.jar"
}

dependencies {
        runtime ('org.compass-project:compass:2.1.4')
        runtime ('org.apache.lucene:lucene-core:2.4.1')
        runtime ('org.apache.lucene:lucene-analyzers:2.4.1')
        runtime ('org.apache.lucene:lucene-highlighter:2.4.1')
        runtime ('org.apache.lucene:lucene-queries:2.4.1')
        runtime ('org.apache.lucene:lucene-snowball:2.4.1')
        runtime ('org.apache.lucene:lucene-spellchecker:2.4.1')
}
Show
Gavin Kromhout added a comment - Ah, I had set dependencies in BuildConfig to get around this and another problem. That pretty much invalidates my comment about it working in previous versions, confirms Gianny DAMOUR's version comment and I can confirm that 0.6-SNAPSHOT is working for me in Grails-1.3.5. My Grails-1.2.2 environment appears to run into a plugin conflict similar to this: http://grails.1312388.n4.nabble.com/Plugin-Incompatibility-Multi-Tenant-Searchable-td1354534.html BuildConfig.groovy code to run compass-2.1.4 in searchable-0.5.5:
grails.war.resources = { stagingDir, args ->
    // Included by searchable plugin.
    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0.jar"
    delete file: "${stagingDir}/WEB-INF/lib/compass-2.1.0-src.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-core.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-analyzers.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-highlighter.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-queries.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-snowball.jar"
    delete file: "${stagingDir}/WEB-INF/lib/lucene-spellchecker.jar"
}

dependencies {
        runtime ('org.compass-project:compass:2.1.4')
        runtime ('org.apache.lucene:lucene-core:2.4.1')
        runtime ('org.apache.lucene:lucene-analyzers:2.4.1')
        runtime ('org.apache.lucene:lucene-highlighter:2.4.1')
        runtime ('org.apache.lucene:lucene-queries:2.4.1')
        runtime ('org.apache.lucene:lucene-snowball:2.4.1')
        runtime ('org.apache.lucene:lucene-spellchecker:2.4.1')
}

People

Vote (10)
Watch (11)

Dates

  • Created:
    Updated:
    Resolved: