About IndexedEmbedded annotation and collection

Hello,

i have 2 questions about IndexedEmbedded annotation:

  • first, with OneToMany annotation which instance is flatten, the first one, the last one or any one ?
  • second, still with OneToMany annotation, i would like to index the collection size, but it seems that we cannot mix IndexedEmbedded and Field annotations ?

Thanks

Hello,

I’ll assume you’re using Hibernate Search 5.11.

All instances are embedded in the index.

So for example if you have a @OneToMany List<Person> people and the list contains two persons, Person[firstname = "John", lastname = "Smith"] and Person[firstname = "Jane", lastname = "Doe"], you will end up with a document containing multi-valued fields: people.firstname = ["John", "Jane"], people.lastname = ["Smith", "Doe"].

Normally you should be able to do it. What is your problem exactly?

I know that, when you use one of the default field bridges, there’s a legacy feature that we have to keep for backward compatibility and that changes the meaning of your @Field when there is an @IndexedEmbedded on the same property; when this happens, the field bridge will be passed each collection element one after another instead of being passed the whole collection.
But in your case you should be using a custom bridge, so I don’t really see what the problem is… ?

In the following example, when we dump document fields from the lucene index, we don’t see the “locationCount” field but we can see fields defined in the “DigitalLocation” entity:

@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "component")
@IndexedEmbedded
@JsonManagedReference
@Field(name="locationCount", analyze = Analyze.NO, bridge = @FieldBridge(impl = CollectionCountBridge.class))
private List<DigitalLocation> locations = null;

Following is the custom bridge we use:

public class CollectionCountBridge implements MetadataProvidingFieldBridge
{
	public void configureFieldMetadata(String name, FieldMetadataBuilder builder) 
	{
		builder.field(name, FieldType.INTEGER);
	}
	
	public void set(String name, Object value, Document document, LuceneOptions luceneOptions) 
	{
		List<?> list = (List<?>) value;
		
		int count = 0;
		
		if (list != null) count = list.size();
		
		luceneOptions.addFieldToDocument(name, String.valueOf(count), document);
	}
}

Something that may be unrelated, but that you may want to fix in your bridge: if you define the type of your field as INTEGER, you should use luceneOptions.addNumericFieldToDocument(name, count, document), not luceneOptions.addFieldToDocument(name, String.valueOf(count), document). The latter adds a text field, which is probably not what you want.

Where are you looking for this value? If the field is only indexed, and not stored, and does not have doc values, “seeing” the per-document value is far from obvious: it’s only present in an inverted index.

If you change your annotation to this:

@Field(name="locationCount", analyze = Analyze.NO, bridge = @FieldBridge(impl = CollectionCountBridge.class), store = Store.YES)

… then do you see something in the dump?

Also, could you run your application in debug mode and put a breakpoint in your bridge’s set() method, to check whether the method is actually called?

Thank you for your help.

It works as expected now, this was due to a bad configuration and not to the code.

Sorry for the inconvenience.