Support runtime polymorphism on associations (instead of defining the indexed properties based on the returned type)

Description

When using @IndexedEmbedded on a set/list of parent/top classes the @Field annotations in the child classes are not picked up and indexed.

@IndexedEmbedded(depth=100)
@OneToMany(fetch = FetchType.LAZY, mappedBy = "top", cascade = CascadeType.ALL)
public Set<Parent> getParents() {
return parents;
}

public class Child extends Parent {
private String childName;
@Field(name = "childName", index=Index.TOKENIZED) // This field is not picked up!!!
.
.
}

Attachments

2

Activity

Show:

Yoann Rodière September 8, 2021 at 10:37 AM

I just thought a bit about this problem while answering to .

One way to solve this would be to apply the mapping differently when applying an @IndexedEmbedded (org.hibernate.search.mapper.pojo.processing.building.impl.PojoIndexingProcessorValueNodeBuilderDelegate#indexedEmbedded). We would apply the mapping for the declared type as usual. But we would also apply the mapping for each sub type with a cast (see what we do for @IndexedEmbedded(targetType = …), except in this case the cast would be allowed to fail). Crucially, we would ignore the mapping of the supertypes when mapping the subtypes (usually we always apply supertype mappings together with subtype mappings).

Perhaps it would be clearer with an example; the resulting indexing processor would look like this:

  • get property values

    • for each value:

      • apply the mapping of A and its supertypes

      • [NEW!] try to cast to B, if successful:

        • apply the mapping of B (but not its supertypes)

      • [NEW!] try to cast to C; if successful:

        • apply the mapping of C (but not its supertypes)

      • [NEW!] try to cast to I, implemented by B and C but not A; if successful:

        • apply the mapping of I (but not its supertypes)

This would work just fine as long as B, C and I have completely disjoint mappings, i.e. they don’t try to override each other.

Support for interfaces implemented by multiple subtypes (like I in this example) might be complex to get right. I’m thinking that during the mapping, we would probably have to expose to binders/etc. something akin to a “union type” of B and C? Maybe we just shouldn’t support it, as a first step.

Yoann Rodière April 16, 2018 at 7:12 AM

I think we should be able to add support for polymorphism in @IndexedEmbedded, e.g. when encountering @IndexedEmbedded private A a;, consider the mapping of not only A, but also its subclasses B, C, ... That would only be possible for entity types, though, where we know all the subtypes upfront.

That being said, there would be some challenges:

  1. This feature would imply defining fields from different classes (B}, C, ...) in the exact same place in the index schema.

    • We would have to allow some conflicts: fields contributed from different entity types with the same name, but the exact same options, or "compatible" options (if one contribution declares the storage type as "default", then it's compatible with another declaring it as "yes" or "no")

    • ... while preventing others: fields contributed from the same entity type, or from a supertype and one of its subtypes, with the same name, fields contributed from different entity types with the same name and different options

  2. This feature could conflict with some support we have for inheritance in 6. For instance if you define a property with type T in entity type A, annotated with @Field, and override the getter in the entity subtype B to have type U (with U extends T), Hibernate Search will correctly look for a bridge taking U as an input. If we have to take into account multiple entity subtypes B, C, D, etc., each overriding the property to have a different type V, W, ... this could get wildly complicated really fast.

  3. This feature would make the indexing process more complex. That would be manageable, but the problem is this would consequently make automatic reindexing when a contained entity changes more complex, too. And that part is already quite complex...

Also worth mentioning, part (if not all) of the problematics mentioned above are very similar to the ones we would face if we allowed multiple indexed types to be stored in the same index in Hibernate Search 6. And we decided against it in order to keep things simple and to not have to work around the decisions that were taken in Elasticsearch 6.

So can have a look, but let's keep in mind this has some implications that make the feature far from trivial to implement.
Moving this to version 6 so that we don't forget to have a look.

Sanne Grinovero April 15, 2018 at 9:45 PM

Hi , good question. We're re-designing the whole DocumentBuilder to address several limitations for Hibernate Search 6, we could explore this idea as well.

I'll talk about it with the team but keep in mind that we'll need to have a full definition of the schema at bootstrap, so there will be need for some limitation. For example I'm thinking we would only be able to include in the upfront-known definition the mapped entities from the domain model - not including other sub types. Even in this case I'm not sure if just guessing that all fields from all subtypes of an indexed type should be considered, people will likely want some more control on this.

How would you see the mapping work best for your use case?

Michael Hum April 13, 2018 at 5:52 PM

This is quite an old ticket, but I am seeing the same behaviour with our application (hibernate 5.1.10.final, search 5.6.4 final).

We have an entity A with field "address" of abstract type B. B has three possible concrete classes: B1, B2, or B3.

Annotating "address" as @IndexedEmbeddable only indexes the fields in the abstract class.

Any updates? Is this a planned feature to add still?

Geir-Magnus Pettersen March 21, 2011 at 9:11 AM

It looks like not much has happened in the last year at least regarding NHibernate.Search. The last commit I can find has this description. Port from H.Search 3.1: Change from loading entities one by one to loading all using the IN clause. But I found the DocumentBuilder class and will start to experiment a little with it. Thanks so far Sanne!

Details

Assignee

Reporter

Components

Priority

Created December 28, 2009 at 4:04 PM
Updated July 12, 2024 at 7:59 AM