Skip to content

Commit

Permalink
Provide the parent nested filter in the NestedMapperBuilderContext
Browse files Browse the repository at this point in the history
  • Loading branch information
jimczi committed May 30, 2024
1 parent 79f12f6 commit 315d3c4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import org.elasticsearch.common.util.ByteUtils;
import org.elasticsearch.features.NodeFeature;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.index.query.support.NestedScope;
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
Expand Down Expand Up @@ -149,7 +148,7 @@ static NameValue decode(Object field) {
// This mapper doesn't contribute to source directly as it has no access to the object structure. Instead, its contents
// are loaded by SourceLoader and passed to object mappers that, in turn, write their ignore fields at the appropriate level.
@Override
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(NestedScope nestedScope) {
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() {
return SourceLoader.SyntheticFieldLoader.NOTHING;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.elasticsearch.index.IndexVersions;
import org.elasticsearch.index.fieldvisitor.LeafStoredFieldLoader;
import org.elasticsearch.index.fieldvisitor.StoredFieldLoader;
import org.elasticsearch.index.query.support.NestedScope;
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
Expand Down Expand Up @@ -69,31 +68,36 @@ Builder includeInParent(boolean includeInParent) {
@Override
public NestedObjectMapper build(MapperBuilderContext context) {
boolean parentIncludedInRoot = this.includeInRoot.value();
final Query parentNestedTypeFilter;
if (context instanceof NestedMapperBuilderContext nc) {
// we're already inside a nested mapper, so adjust our includes
if (nc.parentIncludedInRoot && this.includeInParent.value()) {
this.includeInRoot = Explicit.IMPLICIT_FALSE;
}
parentNestedTypeFilter = nc.nestedTypeFilter;
} else {
// this is a top-level nested mapper, so include_in_parent = include_in_root
parentIncludedInRoot |= this.includeInParent.value();
if (this.includeInParent.value()) {
this.includeInRoot = Explicit.IMPLICIT_FALSE;
}
parentNestedTypeFilter = Queries.newNonNestedFilter(indexCreatedVersion);
}
NestedMapperBuilderContext nestedContext = new NestedMapperBuilderContext(
context.buildFullName(name()),
parentIncludedInRoot,
context.getDynamic(dynamic),
context.getMergeReason()
);
final String fullPath = context.buildFullName(name());
final String nestedTypePath;
if (indexCreatedVersion.before(IndexVersions.V_8_0_0)) {
nestedTypePath = "__" + fullPath;
} else {
nestedTypePath = fullPath;
}
final Query nestedTypeFilter = NestedPathFieldMapper.filter(indexCreatedVersion, nestedTypePath);
NestedMapperBuilderContext nestedContext = new NestedMapperBuilderContext(
context.buildFullName(name()),
nestedTypeFilter,
parentIncludedInRoot,
context.getDynamic(dynamic),
context.getMergeReason()
);
return new NestedObjectMapper(
name(),
fullPath,
Expand All @@ -103,9 +107,9 @@ public NestedObjectMapper build(MapperBuilderContext context) {
includeInParent,
includeInRoot,
nestedTypePath,
NestedPathFieldMapper.filter(indexCreatedVersion, nestedTypePath),
bitSetProducer,
indexCreatedVersion
nestedTypeFilter,
parentNestedTypeFilter,
bitSetProducer
);
}
}
Expand Down Expand Up @@ -146,24 +150,38 @@ protected static void parseNested(String name, Map<String, Object> node, NestedO
private static class NestedMapperBuilderContext extends MapperBuilderContext {

final boolean parentIncludedInRoot;

NestedMapperBuilderContext(String path, boolean parentIncludedInRoot, Dynamic dynamic, MapperService.MergeReason mergeReason) {
final Query nestedTypeFilter;

NestedMapperBuilderContext(
String path,
Query nestedTypeFilter,
boolean parentIncludedInRoot,
Dynamic dynamic,
MapperService.MergeReason mergeReason
) {
super(path, false, false, false, dynamic, mergeReason);
this.parentIncludedInRoot = parentIncludedInRoot;
this.nestedTypeFilter = nestedTypeFilter;
}

@Override
public MapperBuilderContext createChildContext(String name, Dynamic dynamic) {
return new NestedMapperBuilderContext(buildFullName(name), parentIncludedInRoot, getDynamic(dynamic), getMergeReason());
return new NestedMapperBuilderContext(
buildFullName(name),
nestedTypeFilter,
parentIncludedInRoot,
getDynamic(dynamic),
getMergeReason()
);
}
}

private final Explicit<Boolean> includeInRoot;
private final Explicit<Boolean> includeInParent;
private final String nestedTypePath;
private final Query nestedTypeFilter;
private final Query parentNestedTypeFilter;
private final Function<Query, BitSetProducer> bitSetProducer;
private final IndexVersion indexVersionCreated;

NestedObjectMapper(
String name,
Expand All @@ -175,16 +193,16 @@ public MapperBuilderContext createChildContext(String name, Dynamic dynamic) {
Explicit<Boolean> includeInRoot,
String nestedTypePath,
Query nestedTypeFilter,
Function<Query, BitSetProducer> bitSetProducer,
IndexVersion indexVersionCreated
Query parentNestedTypeFilter,
Function<Query, BitSetProducer> bitSetProducer
) {
super(name, fullPath, enabled, Explicit.IMPLICIT_TRUE, Explicit.IMPLICIT_FALSE, dynamic, mappers);
this.nestedTypePath = nestedTypePath;
this.nestedTypeFilter = nestedTypeFilter;
this.parentNestedTypeFilter = parentNestedTypeFilter;
this.includeInParent = includeInParent;
this.includeInRoot = includeInRoot;
this.bitSetProducer = bitSetProducer;
this.indexVersionCreated = indexVersionCreated;
}

public Query nestedTypeFilter() {
Expand Down Expand Up @@ -234,8 +252,8 @@ NestedObjectMapper withoutMappers() {
includeInRoot,
nestedTypePath,
nestedTypeFilter,
bitSetProducer,
indexVersionCreated
parentNestedTypeFilter,
bitSetProducer
);
}

Expand Down Expand Up @@ -305,8 +323,8 @@ public ObjectMapper merge(Mapper mergeWith, MapperMergeContext parentMergeContex
incInRoot,
nestedTypePath,
nestedTypeFilter,
bitSetProducer,
indexVersionCreated
parentNestedTypeFilter,
bitSetProducer
);
}

Expand All @@ -320,6 +338,7 @@ protected MapperMergeContext createChildContext(MapperMergeContext mapperMergeCo
return mapperMergeContext.createChildContext(
new NestedMapperBuilderContext(
mapperBuilderContext.buildFullName(name),
nestedTypeFilter,
parentIncludedInRoot,
mapperBuilderContext.getDynamic(dynamic),
mapperBuilderContext.getMergeReason()
Expand All @@ -328,21 +347,15 @@ protected MapperMergeContext createChildContext(MapperMergeContext mapperMergeCo
}

@Override
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(NestedScope nestedScope) {
final NestedObjectMapper mapper = this;
SourceLoader sourceLoader = new SourceLoader.Synthetic(() -> {
nestedScope.nextLevel(mapper);
try {
return super.syntheticFieldLoader(nestedScope, mappers.values().stream(), true);
} finally {
nestedScope.previousLevel();
}
}, NOOP);
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() {
SourceLoader sourceLoader = new SourceLoader.Synthetic(() -> super.syntheticFieldLoader(mappers.values().stream(), true), NOOP);
var storedFieldsLoader = StoredFieldLoader.create(false, sourceLoader.requiredStoredFields());
var parentFilter = nestedScope.getObjectMapper() == null
? Queries.newNonNestedFilter(indexVersionCreated)
: nestedScope.getObjectMapper().nestedTypeFilter();
return new NestedFieldLoader(storedFieldsLoader, sourceLoader, () -> bitSetProducer.apply(parentFilter), nestedTypeFilter);
return new NestedFieldLoader(
storedFieldsLoader,
sourceLoader,
() -> bitSetProducer.apply(parentNestedTypeFilter),
nestedTypeFilter
);
}

private class NestedFieldLoader implements SourceLoader.SyntheticFieldLoader {
Expand Down Expand Up @@ -382,11 +395,26 @@ public DocValuesLoader docValuesLoader(LeafReader leafReader, int[] docIdsInLeaf
var childScorer = searcher.createWeight(childFilter, ScoreMode.COMPLETE_NO_SCORES, 1f).scorer(leafReader.getContext());
var parentDocs = parentBitSetProducer.get().getBitSet(leafReader.getContext());
return parentDoc -> {
this.children = childScorer != null ? getChildren(parentDoc, parentDocs, childScorer.iterator()) : List.of();
this.children = childScorer != null ? collectChildren(parentDoc, parentDocs, childScorer.iterator()) : List.of();
return children.size() > 0;
};
}

private List<Integer> collectChildren(int parentDoc, BitSet parentDocs, DocIdSetIterator childIt) throws IOException {
assert parentDocs.get(parentDoc) : "wrong context, doc " + parentDoc + " is not a parent of " + nestedTypePath;
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
int childDocId = childIt.docID();
if (childDocId <= prevParentDoc) {
childDocId = childIt.advance(prevParentDoc + 1);
}

List<Integer> res = new ArrayList<>();
for (; childDocId < parentDoc; childDocId = childIt.nextDoc()) {
res.add(childDocId);
}
return res;
}

@Override
public boolean hasValue() {
return children.size() > 0;
Expand Down Expand Up @@ -421,18 +449,4 @@ public String fieldName() {
return name();
}
}

private static List<Integer> getChildren(int parentDoc, BitSet parentDocs, DocIdSetIterator childIt) throws IOException {
final int prevParentDoc = parentDocs.prevSetBit(parentDoc - 1);
int childDocId = childIt.docID();
if (childDocId <= prevParentDoc) {
childDocId = childIt.advance(prevParentDoc + 1);
}

List<Integer> res = new ArrayList<>();
for (; childDocId < parentDoc; childDocId = childIt.nextDoc()) {
res.add(childDocId);
}
return res;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.elasticsearch.index.IndexVersion;
import org.elasticsearch.index.IndexVersions;
import org.elasticsearch.index.mapper.MapperService.MergeReason;
import org.elasticsearch.index.query.support.NestedScope;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder;

Expand Down Expand Up @@ -757,21 +756,21 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep

}

public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(NestedScope nestedScope, Stream<Mapper> mappers) {
return syntheticFieldLoader(nestedScope, mappers, false);
SourceLoader.SyntheticFieldLoader syntheticFieldLoader(Stream<Mapper> mappers) {
return syntheticFieldLoader(mappers, false);
}

protected SourceLoader.SyntheticFieldLoader syntheticFieldLoader(NestedScope nestedScope, Stream<Mapper> mappers, boolean isFragment) {
protected SourceLoader.SyntheticFieldLoader syntheticFieldLoader(Stream<Mapper> mappers, boolean isFragment) {
var fields = mappers.sorted(Comparator.comparing(Mapper::name))
.map(mapper -> mapper.syntheticFieldLoader(nestedScope))
.map(Mapper::syntheticFieldLoader)
.filter(l -> l != SourceLoader.SyntheticFieldLoader.NOTHING)
.toList();
return new SyntheticSourceFieldLoader(fields, isFragment);
}

@Override
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(NestedScope nestedScope) {
return syntheticFieldLoader(nestedScope, mappers.values().stream());
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() {
return syntheticFieldLoader(mappers.values().stream());
}

private class SyntheticSourceFieldLoader implements SourceLoader.SyntheticFieldLoader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ public FieldMapper.Builder getMergeBuilder() {
*/
public SourceLoader newSourceLoader(Mapping mapping, SourceFieldMetrics metrics) {
if (mode == Mode.SYNTHETIC) {
return new SourceLoader.Synthetic(mapping, metrics);
return new SourceLoader.Synthetic(mapping::syntheticFieldLoader, metrics);
}
return SourceLoader.FROM_STORED_SOURCE;
}
Expand Down

0 comments on commit 315d3c4

Please sign in to comment.