Searching on a numeric field that was indexed through an {{@IndexedEmbedded}} will return each and every document (i.e. the filter won't apply) for a {{\[value TO *\]}} query and will return no document for a {{\[value1 TO value2\]}} query. This happens when using the Hibernate Search DSL to build range queries.
I ran the test case in debug mode, and it seems that the problem starts here when building the query: {code:java} // Showing org.hibernate.search.query.dsl.impl.ConnectedMultiFieldsRangeQueryBuilder.createQuery(FieldContext, ConversionContext)) private Query createQuery(FieldContext fieldContext, ConversionContext conversionContext) { final Query perFieldQuery; final String fieldName = fieldContext.getField();
FieldDescriptor fieldDescriptor = queryContext.getFactory().getIndexedTypeDescriptor( queryContext.getEntityType() ).getIndexedField( fieldName ); if ( fieldDescriptor != null ) { if ( FieldDescriptor.Type.NUMERIC.equals( fieldDescriptor.getType() ) ) { perFieldQuery = createNumericRangeQuery( fieldName, rangeContext ); } else { perFieldQuery = createKeywordRangeQuery( fieldName, rangeContext, queryContext, conversionContext, fieldContext ); } } else { //we need to guess the proper type from the parameter types (Fallback logic required by the protobuf integration in Infinispan) if ( rangeBoundaryTypeRequiredNumericQuery( rangeContext.getFrom(), rangeContext.getTo() ) ) { perFieldQuery = createNumericRangeQuery( fieldName, rangeContext ); } else { perFieldQuery = createKeywordRangeQuery( fieldName, rangeContext, queryContext, conversionContext, fieldContext ); } }
return fieldContext.getFieldCustomizer().setWrappedQuery( perFieldQuery ).createQuery(); } {code}
The problem is that {{fieldDescriptor}} is null for embedded fields, which makes the DSL fall back to some Infinispan-related magic, which doesn't consider Date to be a numeric indexed type. This the query becomes a keyword-range query ( ?) instead of a numeric-range query.
I searched around a little, and indeed it seems that this method, which initializes the field descriptors of a type descriptor, doesn't consider embedded fields:
{code:java} // Showing org.hibernate.search.metadata.impl.IndexedTypeDescriptorImpl.createAllFieldDescriptors() private Map<String, FieldDescriptor> createAllFieldDescriptors() { Map<String, FieldDescriptor> fieldDescriptorMap = new HashMap<String, FieldDescriptor>(); for ( FieldDescriptor fieldDescriptor : classBridgeFieldDescriptors ) { fieldDescriptorMap.put( fieldDescriptor.getName(), fieldDescriptor ); } for ( PropertyDescriptor propertyDescriptor : propertyDescriptors ) { for ( FieldDescriptor fieldDescriptor : propertyDescriptor.getIndexedFields() ) { fieldDescriptorMap.put( fieldDescriptor.getName(), fieldDescriptor ); } } return fieldDescriptorMap; } {code}
The property descriptors don't include the embedded fields, since they are built that way:
{code:java} // Showing org.hibernate.search.metadata.impl.IndexedTypeDescriptorImpl.createOrMergePropertyDescriptor(Map<String, PropertyDescriptor>, PropertyMetadata) private void createOrMergePropertyDescriptor(Map<String, PropertyDescriptor> propertyDescriptorsTmp, PropertyMetadata propertyMetadata) { String propertyName = propertyMetadata.getPropertyAccessorName(); Set<FieldDescriptor> tmpSet = new HashSet<FieldDescriptor>(); if ( propertyDescriptorsTmp.containsKey( propertyName ) ) { tmpSet.addAll( propertyDescriptorsTmp.get( propertyName ).getIndexedFields() ); }
boolean id = false; for ( DocumentFieldMetadata documentFieldMetadata : propertyMetadata.getFieldMetadataSet() ) { if ( documentFieldMetadata.isId() ) { id = true; } FieldDescriptor fieldDescriptor; if ( documentFieldMetadata.isNumeric() ) { fieldDescriptor = new NumericFieldDescriptorImpl( documentFieldMetadata ); } else { fieldDescriptor = new FieldDescriptorImpl( documentFieldMetadata ); } tmpSet.add( fieldDescriptor ); } PropertyDescriptor propertyDescriptor = new PropertyDescriptorImpl( propertyMetadata.getPropertyAccessorName(), id, tmpSet );
propertyDescriptorsTmp.put( propertyDescriptor.getName(), propertyDescriptor ); } {code}
... which won't do since the {{fieldMetadataSet}} on {{propertyMetadata}} doesn't include embedded fields.
I see two solutions:
1. Either we change the propertyMetadata so that it also includes a embeddedFieldsMetadataSet (and we initialize it, and we use it in {{createOrMergePropertyDescriptor()}}) 2. OR we change IndexedTypeDescriptorImpl so that, in some way, it uses {{typeMetadata.getEmbeddedTypeMetadata()}} in the {{createAllFieldDescriptors()}} method.
Test case coming here : https://github . com/hibernate/hibernate-search/pull/958 |
|