Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make use of global ordinals in parent/child queries #5846

Closed
wants to merge 10 commits into from
Expand Up @@ -129,6 +129,10 @@ public BytesValues.WithOrdinals getBytesValues(String type) {
}
}

public WithOrdinals getAtomicFieldData(String type) {
return typeToIds.get(type);
}

@Override
public ScriptDocValues getScriptValues() {
return new ScriptDocValues.Strings(getBytesValues(false));
Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.PagedBytes;
import org.apache.lucene.util.packed.MonotonicAppendingLongBuffer;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.breaker.MemoryCircuitBreaker;
import org.elasticsearch.common.collect.ImmutableOpenMap;
Expand Down Expand Up @@ -57,17 +58,19 @@ public class ParentChildIndexFieldData extends AbstractIndexFieldData<ParentChil

private final NavigableSet<BytesRef> parentTypes;
private final CircuitBreakerService breakerService;
private final GlobalOrdinalsBuilder globalOrdinalsBuilder;

// If child type (a type with _parent field) is added or removed, we want to make sure modifications don't happen
// while loading.
private final Object lock = new Object();

public ParentChildIndexFieldData(Index index, @IndexSettings Settings indexSettings, FieldMapper.Names fieldNames,
FieldDataType fieldDataType, IndexFieldDataCache cache, MapperService mapperService,
CircuitBreakerService breakerService) {
CircuitBreakerService breakerService, GlobalOrdinalsBuilder globalOrdinalsBuilder) {
super(index, indexSettings, fieldNames, fieldDataType, cache);
parentTypes = new TreeSet<>(BytesRef.getUTF8SortedAsUnicodeComparator());
this.breakerService = breakerService;
this.globalOrdinalsBuilder = globalOrdinalsBuilder;
for (DocumentMapper documentMapper : mapperService) {
beforeCreate(documentMapper);
}
Expand Down Expand Up @@ -155,6 +158,11 @@ public ParentChildAtomicFieldData loadDirect(AtomicReaderContext context) throws
}
}

public WithOrdinals getGlobalParentChild(String type, IndexReader indexReader) {
PerParentTypeGlobalOrdinals perParentType = new PerParentTypeGlobalOrdinals(type);
return perParentType.loadGlobal(indexReader);
}

@Override
public void beforeCreate(DocumentMapper mapper) {
synchronized (lock) {
Expand Down Expand Up @@ -201,7 +209,8 @@ public static class Builder implements IndexFieldData.Builder {
public IndexFieldData<?> build(Index index, @IndexSettings Settings indexSettings, FieldMapper<?> mapper,
IndexFieldDataCache cache, CircuitBreakerService breakerService,
MapperService mapperService, GlobalOrdinalsBuilder globalOrdinalBuilder) {
return new ParentChildIndexFieldData(index, indexSettings, mapper.names(), mapper.fieldDataType(), cache, mapperService, breakerService);
return new ParentChildIndexFieldData(index, indexSettings, mapper.names(), mapper.fieldDataType(), cache,
mapperService, breakerService, globalOrdinalBuilder);
}
}

Expand Down Expand Up @@ -254,4 +263,87 @@ public void afterLoad(TermsEnum termsEnum, long actualUsed) {
}
}

private final class PerParentTypeGlobalOrdinals implements WithOrdinals {

private final String type;

public PerParentTypeGlobalOrdinals(String type) {
this.type = type;
}

@Override
public AtomicFieldData.WithOrdinals load(AtomicReaderContext context) {
return loadDirect(context);
}

@Override
public AtomicFieldData.WithOrdinals loadDirect(AtomicReaderContext context) {
ParentChildAtomicFieldData parentChildAtomicFieldData = ParentChildIndexFieldData.this.load(context);
AtomicFieldData.WithOrdinals typeAfd = parentChildAtomicFieldData.getAtomicFieldData(type);
if(typeAfd != null) {
return typeAfd;
} else {
return PagedBytesAtomicFieldData.empty(context.reader().maxDoc());
}
}

@Override
public WithOrdinals loadGlobal(IndexReader indexReader) {
if (indexReader.leaves().size() <= 1) {
// ordinals are already global
return this;
}

try {
return cache.load(indexReader, this);
} catch (Throwable e) {
if (e instanceof ElasticsearchException) {
throw (ElasticsearchException) e;
} else {
throw new ElasticsearchException(e.getMessage(), e);
}
}
}

@Override
public WithOrdinals localGlobalDirect(IndexReader indexReader) throws Exception {
return globalOrdinalsBuilder.build(indexReader, this, indexSettings, breakerService);
}

@Override
public FieldMapper.Names getFieldNames() {
return ParentChildIndexFieldData.this.getFieldNames();
}

@Override
public FieldDataType getFieldDataType() {
return ParentChildIndexFieldData.this.getFieldDataType();
}

@Override
public boolean valuesOrdered() {
return ParentChildIndexFieldData.this.valuesOrdered();
}

@Override
public XFieldComparatorSource comparatorSource(@Nullable Object missingValue, SortMode sortMode) {
throw new UnsupportedOperationException();
}

@Override
public void clear() {

}

@Override
public void clear(IndexReader reader) {

}

@Override
public Index index() {
return ParentChildIndexFieldData.this.index();
}
}

}