Skip to content

Commit 14b0e2b

Browse files
committed
HSEARCH-3905 Add parent object field path to the "field_names" field when a value is added to a dynamic child field
This will allow detection of these dynamic children fields when executing an "exists" predicate on the object field. Signed-off-by: Yoann Rodière <yoann@hibernate.org>
1 parent c8a946e commit 14b0e2b

File tree

5 files changed

+58
-8
lines changed

5 files changed

+58
-8
lines changed

backend/lucene/src/main/java/org/hibernate/search/backend/lucene/document/impl/AbstractLuceneDocumentElementBuilder.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@ void contribute(MultiTenancyStrategy multiTenancyStrategy, String tenantId, Stri
158158
}
159159
}
160160

161+
/**
162+
* When executing an exists() predicate on an object field that contains dynamic value field,
163+
* we don't necessarily know all the possible child value fields,
164+
* so we cannot just execute {@code exists(childField1) OR exists(childField2) OR ... OR exists(childFieldN)}.
165+
* That's why we keep track of the fact that
166+
* "for this document, this object field exists because it contains at least one dynamic value".
167+
* This is done by adding the path of the object field to the "fieldNames" field.
168+
*/
169+
abstract void ensureDynamicValueDetectedByExistsPredicateOnObjectField();
170+
161171
private <F> void addValue(LuceneIndexSchemaValueFieldNode<F> node, F value) {
162172
LuceneIndexSchemaObjectNode expectedParentNode = node.parent();
163173
checkTreeConsistency( expectedParentNode );
@@ -170,6 +180,9 @@ private <F> void addValue(LuceneIndexSchemaValueFieldNode<F> node, F value) {
170180
}
171181

172182
type.codec().addToDocument( documentContent, absolutePath, value );
183+
if ( value != null && node.dynamic() ) {
184+
ensureDynamicValueDetectedByExistsPredicateOnObjectField();
185+
}
173186
}
174187

175188
private DocumentElement addObject(LuceneIndexSchemaObjectFieldNode node, boolean nullObject) {
@@ -189,12 +202,12 @@ private DocumentElement addObject(LuceneIndexSchemaObjectFieldNode node, boolean
189202
switch ( node.structure() ) {
190203
case NESTED:
191204
LuceneNestedObjectFieldBuilder nestedDocumentBuilder =
192-
new LuceneNestedObjectFieldBuilder( model, node );
205+
new LuceneNestedObjectFieldBuilder( model, node, this );
193206
addNestedObjectDocumentBuilder( nestedDocumentBuilder );
194207
return nestedDocumentBuilder;
195208
default:
196209
LuceneFlattenedObjectFieldBuilder flattenedDocumentBuilder =
197-
new LuceneFlattenedObjectFieldBuilder( model, node, documentContent );
210+
new LuceneFlattenedObjectFieldBuilder( model, node, this, documentContent );
198211
addFlattenedObjectDocumentBuilder( flattenedDocumentBuilder );
199212
return flattenedDocumentBuilder;
200213
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Hibernate Search, full-text search for your domain model
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.search.backend.lucene.document.impl;
8+
9+
import org.hibernate.search.backend.lucene.document.model.impl.LuceneIndexModel;
10+
import org.hibernate.search.backend.lucene.document.model.impl.LuceneIndexSchemaObjectFieldNode;
11+
12+
class AbstractLuceneObjectFieldBuilder extends AbstractLuceneDocumentElementBuilder {
13+
14+
private final AbstractLuceneDocumentElementBuilder parent;
15+
16+
AbstractLuceneObjectFieldBuilder(LuceneIndexModel model, LuceneIndexSchemaObjectFieldNode schemaNode,
17+
AbstractLuceneDocumentElementBuilder parent, LuceneDocumentContentImpl documentContent) {
18+
super( model, schemaNode, documentContent );
19+
this.parent = parent;
20+
}
21+
22+
@Override
23+
void ensureDynamicValueDetectedByExistsPredicateOnObjectField() {
24+
documentContent.addFieldName( schemaNode.absolutePath() );
25+
if ( schemaNode.dynamic() ) {
26+
// If this object field is dynamic,
27+
// the parent object's metadata will not include it, so we must propagate the information.
28+
parent.ensureDynamicValueDetectedByExistsPredicateOnObjectField();
29+
}
30+
}
31+
}

backend/lucene/src/main/java/org/hibernate/search/backend/lucene/document/impl/LuceneFlattenedObjectFieldBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@
1515
import org.hibernate.search.backend.lucene.logging.impl.Log;
1616
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
1717

18-
class LuceneFlattenedObjectFieldBuilder extends AbstractLuceneDocumentElementBuilder {
18+
class LuceneFlattenedObjectFieldBuilder extends AbstractLuceneObjectFieldBuilder {
1919

2020
private static final Log log = LoggerFactory.make( Log.class, MethodHandles.lookup() );
2121

2222
private final Set<String> encounteredFields = new HashSet<>();
2323

2424
LuceneFlattenedObjectFieldBuilder(LuceneIndexModel model, LuceneIndexSchemaObjectFieldNode schemaNode,
25-
LuceneDocumentContentImpl documentContent) {
25+
AbstractLuceneDocumentElementBuilder parent, LuceneDocumentContentImpl documentContent) {
2626
// The document content is not ours: it's the parent's.
27-
super( model, schemaNode, documentContent );
27+
super( model, schemaNode, parent, documentContent );
2828
}
2929

3030
@Override

backend/lucene/src/main/java/org/hibernate/search/backend/lucene/document/impl/LuceneNestedObjectFieldBuilder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
import org.apache.lucene.document.Document;
1717

1818

19-
class LuceneNestedObjectFieldBuilder extends AbstractLuceneDocumentElementBuilder {
19+
class LuceneNestedObjectFieldBuilder extends AbstractLuceneObjectFieldBuilder {
2020

21-
LuceneNestedObjectFieldBuilder(LuceneIndexModel model, LuceneIndexSchemaObjectFieldNode schemaNode) {
22-
super( model, schemaNode, new LuceneDocumentContentImpl() );
21+
LuceneNestedObjectFieldBuilder(LuceneIndexModel model, LuceneIndexSchemaObjectFieldNode schemaNode,
22+
AbstractLuceneDocumentElementBuilder parent) {
23+
super( model, schemaNode, parent, new LuceneDocumentContentImpl() );
2324
}
2425

2526
@Override

backend/lucene/src/main/java/org/hibernate/search/backend/lucene/document/impl/LuceneRootDocumentBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public LuceneIndexEntry build(String tenantId, String id, String routingKey) {
3232
);
3333
}
3434

35+
@Override
36+
void ensureDynamicValueDetectedByExistsPredicateOnObjectField() {
37+
// This is not an object field: nothing to do.
38+
}
39+
3540
private List<Document> assembleDocuments(MultiTenancyStrategy multiTenancyStrategy,
3641
String tenantId, String id, String routingKey) {
3742
// We own the document content, so we finalize it ourselves.

0 commit comments

Comments
 (0)