@org.hibernate.search.annotations.IndexedEmbedded and polymorphic associations.

While configuring my client model with Hibernate Search annotations
I encountered the following problem:

<pre class="brush: java;"> 

@Entity
@org.hibernate.search.annotations.Indexed
public class Form {
    ....
    @org.hibernate.search.annotations.Field   
    private String name;
   
    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "join_form_input", joinColumns = @JoinColumn(name = "form_id"), inverseJoinColumns = @JoinColumn(name = "input_id"))
    @org.hibernate.search.annotations.IndexedEmbedded
    private List<Input> fields = new ArrayList<Input>();
   
    ....
}


@Inheritance
@Entity
@DiscriminatorColumn(name = "type")
public abstract class Input {
   
    @org.hibernate.search.annotations.Field(index = Index.UN_TOKENIZED)
    @Column(insertable = false, updatable = false)   
    private String type;
   
    some common properties and methods inherited by all Input's subclasses
    ...
}


@Entity
@DiscriminatorValue(value = "Comment")
public class Comment extends Input {
    @org.hibernate.search.annotations.Field   
    private String comment;
    ...
}

@Entity
@DiscriminatorValue(value = "Address")
public class Address extends Input {
    @org.hibernate.search.annotations.Field   
    private String street;
    @org.hibernate.search.annotations.Field   
    private String city;
    @org.hibernate.search.annotations.Field   
    private String postcode;
    @org.hibernate.search.annotations.Field   
    private Integer number;
    ...
}   
    // and around 10 more inputs types as such.
</pre>

It appears when using this configuration, that only Fields in the super class - Input, were indexed, the comment field and address fields were ignored by hibernate search.

@org.hibernate.search.annotations.IndexedEmbedded does not support polymorphic associations.

Keeping in mind the client's requirements, the index mapping should be used to query Forms by type and value, such that value is a String that could much any of the Inputs properties  (No need to query a single and specific Input property).
I thought of 2 options:

1. Map each subclass with its own collection in class Form

But there are a few drawbacks for taking this route

1. I had no use case of using form.getAddreses() or form.getComments() and all other at all.
2. Even if I map these associations as lazy and reducing performance damage of unnecessary joins, having such unused fields could be very confusing
3. Whenever a new Input subclass is added - a new association should be defined but nothing to force this design except bad search result           


2. Add to the Input class the abstract method:

<snippet class="brush: java;"> 

    @org.hibernate.search.annotations.Field
    @Transient
    public abstract String getValue();
</snippet>
   
To force all Input subclasses to implement it. Each input will return the concatenation of all its field's non null values, separated by a space.

This way I'll get an Index field which is Transient to the DB and can be queried to retrieve it's Form.
Also, no damage to performance and a more generic solution. On a case were a new subclass is added design is forced by the abstract method.

But, one drawback is that  all properties of Input subclasses are treated as one single field, which means that they will share the same configuration:
analyzer, Boost, FieldBridge, Index, Store, TermVector.

Any other ideas?

Thanks!



 

Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com