apparna (13) [Avatar] Offline
#1
I have a quick question. I have annotated my entity Person with the correct annotations. Insert and Update worked fine but when I delete, I noticed that my custom backend receives a DeleteLuceneWork and AddLuceneWork intead of just the DeleteLuceneWork item. Why is that happening? It looks like I'm doing something wrong..

Thanks,
Apparna
john.griffin (36) [Avatar] Offline
#2
Re: Delete
Apparna,

Lucene, which is the underlying engine of Hibernate Search has no update call per se. It deletes the old record and then inserts the new record. That's what you are seeing.

John G.
john.griffin (36) [Avatar] Offline
#3
Re: Delete
Aparna,

Hold on, I mis-read your message. Exactly what do you mean by your 'custom back-end'?

John G.
apparna (13) [Avatar] Offline
#4
Re: Delete
Custom back-end takes the lucene data and writes to the database.
I understand that "Update" is "Delete" + "Insert" but "Delete" operation should be just "Delete" right?
emmanuel.bernard (101) [Avatar] Offline
#5
Re: Delete
Delete could mean update on an associated entity (@IndexedEmbedded, @ContainedIn)
Can you give us more details about your domain model (keep it simple if possible)?
apparna (13) [Avatar] Offline
#6
Re: Delete
Its actually simple embedded objects. Person contains Address, Email addresses etc. So I have used @IndexedEmbedded and not @ContainedIn.

Person has First Name, Last Name as @Field and Email Address marked w/"IndexedEmbedded".

EmailAddress has getAddress() marked as @Field

QuickNote: Since I didn't want any kind of optimization done by Lucene, since it's taken care of it by DB, I used @Field(Index=Index.NO, Store=Store.YES). I don't think it should make any difference..

@Indexed
public class Person
{
//Ignoring whole bunch of fields that aren't indexed

@OneToMany( fetch = FetchType.EAGER, cascade = { CascadeType.MERGE,
CascadeType.PERSIST } )
@Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN )
@JoinColumn( name = "PERSON_FK" )
@IndexedEmbedded
private Set<EmailAddressType> m_emailAddressSet =
new HashSet<EmailAddressType>();

@Field( name = "Content", store = Store.YES, index = Index.NO )
public String getFirstName()
{
return m_firstName;
}

@FieldBridge( impl = DenormalizedContentBridge.class )
@Field( name = "Content", store = Store.YES, index = Index.NO )
public String getLastName()
{
return m_lastName;
}


//Ignoring the rest

}

@Embeddable
public class EmailAddressType implements Serializable
{

//Ignorning stuff here..

@Field( store = Store.YES, index = Index.NO )
@FieldBridge( impl = DenormalizedContentBridge.class )
public String getAddress()
{
return m_address;
}

}
emmanuel.bernard (101) [Avatar] Offline
#7
Re: Delete
can you also show how emailaddresstype is mapped and how you delete your person object?
apparna (13) [Avatar] Offline
#8
Re: Delete
This is how EmailAddressType is mapped in the Person class

@OneToMany( fetch = FetchType.EAGER, cascade = { CascadeType.MERGE,
CascadeType.PERSIST } )
@Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN )
@JoinColumn( name = "PERSON_FK" )
@IndexedEmbedded
private Set<EmailAddressType> m_emailAddressSet =
new HashSet<EmailAddressType>();

This is how we delete Person

getEntityManager().remove(getEntityManager().merge( m_person ) );

When I turned on the hibernate debug,
I noticed I get an update on the EmailAddressType before a delete on the Person table. May be its because of this "@Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN )"
emmanuel.bernard (101) [Avatar] Offline
#9
Re: Delete
we are getting closer

Can you show the EmailAddressType mapping (not the association mapping smilie and how you change Person / EmailAddressType before you apply merge on it?

It seems that merge considers that Person or EmailAddressType has changed and raises an update. Then you call for remove.
That's why add and delete are added to the work queue.

So you need to understand why merge triggers an update.
apparna (13) [Avatar] Offline
#10
Re: Delete
I thought I had EmailAddressType mapping in my original post.. Did I miss something?

@Entity
@Embeddable
public class EmailAddressType implements Serializable
{

//Ignorning stuff here..

@Field( store = Store.YES, index = Index.NO )
@FieldBridge( impl = DenormalizedContentBridge.class )
public String getAddress()
{
return m_address;
}

}

Here is I how I delete it


person = customerCruder.createPerson( person );

// Get ID
Long customerId = person.getId();

// Find the customer by ID
person = customerCruder.findPersonById( customerId );

// Delete customer
customerCruder.deletePerson( person );

//DeletePerson internally calls
getEntityManager().remove(getEntityManager().merge( m_person ) );

I noticed if I remove @Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN ) from the person entity, then I just get the DeleteLuceneWork.


It seems that merge considers that Person or EmailAddressType has changed and raises an update. Then you call for remove.
That's why add and delete are added to the work queue.


Even if that's the case, shouldn't I have got 3 items, DeleteLucene, InsertLucene, DeleteLucene (first two for the update and 3rd delete for delete operation) in the queue?
emmanuel.bernard (101) [Avatar] Offline
#11
Re: Delete
it looks like an Hibernate Core unnecessary update trigger.

Hibernate Search will not put twice the same work on the same entity in a given work queue: DeleteLucene, InsertLucene, DeleteLucene cannot happen. This is an optimization we did early on.
apparna (13) [Avatar] Offline
#12
Re: Delete
So how I do I get rid of the unnecessary update that HCore uses?
emmanuel.bernard (101) [Avatar] Offline
#13
Re: Delete
it would be nice to open a JIRA issue with a test case on the hibernate project. This should not happen from what I can tell
apparna (13) [Avatar] Offline
#14
Re: Delete
I found out what's causing the update and the delete.

Here is what is happening...
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name = "DISC", discriminatorType = DiscriminatorType.STRING )
ClassA
{
@OneToOne( fetch = FetchType.EAGER )
@JoinColumn( name = "DEFAULT_EMAILADDRESS_FK" )
private EmailAddressType m_defaultEmailAddress;

}

@Entity
Person extends ClassA
{

@OneToMany( fetch = FetchType.EAGER, cascade = { CascadeType.MERGE,
CascadeType.PERSIST } )
@Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN )
@JoinColumn( name = "PERSON_FK" )

@IndexedEmbedded
private Set<EmailAddressType> m_emailAddressSet =
new HashSet<EmailAddressType>();
}

@Entity
public class EmailAddressType
{

}

Here the test code


person = customerCruder.createPerson( person );

// Get ID
Long customerId = person.getId();

// Find the customer by ID
person = customerCruder.findPersonById( customerId );

// Delete customer
customerCruder.deletePerson( person );

//DeletePerson internally calls
getEntityManager().remove(getEntityManager().merge( m_person ) );

Since its single table per hierarchy, ClassA and person are in the same physical table.

When I delete a person, it performs an update first on the classA table because of the FK(DEFAULT_EMAILADDRESS_FK) and then goes ahead and deletes email addresses and Person record. The problem is it sends out both Update and Delete which seems valid in this use case and HSearch ignores the delete.

Within a transaction if an entity gets updated and deleted, will Hibernate send out two requests to database or just one delete?

Is there a way to remove the optimization from HSearch?

Please let me know..

-Apparna
emmanuel.bernard (101) [Avatar] Offline
#15
Re: Delete
can you attach a minimal test case here
http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-257

I have a fix but I need a test
apparna (13) [Avatar] Offline
#16
Re: Delete
Great! Thanks for your quick response. I will attach a test case today. Will you able to patch the fix for HSearch 3.0.1 GA? If not, I'll have to change the persistence model to make it work..

Thanks,
Apparna
s.grinovero (26) [Avatar] Offline
#17
Re: Delete
Hello,
I see this test is still missing;
There's going to be a release very soon, if you could provide the test we could close this issue.
apparna (13) [Avatar] Offline
#18
Re: Delete
I'll update it with a test in a day.. Can it wait till Wednesday or do you need it sooner?
s.grinovero (26) [Avatar] Offline
#19
Re: Delete
thank you very much;
I think it can wait.
emmanuel.bernard (101) [Avatar] Offline
#20
Re: Delete
Wednesday is good.
Thanks for the extra hand.
emmanuel.bernard (101) [Avatar] Offline
#21
Re: Delete
But Friday is not smilie
claesen (2) [Avatar] Offline
#22
Re: Delete
I'm having the same problem as apparna and I downloaded the latest source (3.1.0beta2) to check the fix. I noticed an issue in the addWorkToQueue function in the DocumentBuilder class. If the work type is delete and there is an AddLuceneWork for the same entity in the queue it is added to the toDelete list. But when looping through the toDelete list the items are not removed from the LuceneWork queue, only from the toDelete list.

I haven't tested the new source yet, will get report back if I find more issues.

Thanks!
emmanuel.bernard (101) [Avatar] Offline
#23
Re: Delete
Can you open a JIRA issue with your remarks and mark it for 3.1.0.CR1 so that we don't forget.
claesen (2) [Avatar] Offline
#24
Re: Delete
Done. The issue number is HSEARCH-293.