diff --git a/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesConsumerWrapper.java b/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesConsumerWrapper.java
new file mode 100644
index 0000000000000..01f139cad8379
--- /dev/null
+++ b/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesConsumerWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.apache.lucene.codecs.lucene90;
+
+import org.apache.lucene.codecs.DocValuesConsumer;
+import org.apache.lucene.index.SegmentWriteState;
+
+import java.io.IOException;
+
+/**
+ * This class is an abstraction of the {@link DocValuesConsumer} for the Star Tree index structure.
+ * It is responsible to consume various types of document values (numeric, binary, sorted, sorted numeric,
+ * and sorted set) for fields in the Star Tree index.
+ *
+ * @opensearch.experimental
+ */
+public class Lucene90DocValuesConsumerWrapper {
+
+ private final Lucene90DocValuesConsumer lucene90DocValuesConsumer;
+
+ public Lucene90DocValuesConsumerWrapper(
+ SegmentWriteState state,
+ String dataCodec,
+ String dataExtension,
+ String metaCodec,
+ String metaExtension
+ ) throws IOException {
+ lucene90DocValuesConsumer = new Lucene90DocValuesConsumer(state, dataCodec, dataExtension, metaCodec, metaExtension);
+ }
+
+ public Lucene90DocValuesConsumer getLucene90DocValuesConsumer() {
+ return lucene90DocValuesConsumer;
+ }
+}
diff --git a/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesProducerWrapper.java b/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesProducerWrapper.java
new file mode 100644
index 0000000000000..884d1b3b48859
--- /dev/null
+++ b/server/src/main/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesProducerWrapper.java
@@ -0,0 +1,52 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.apache.lucene.codecs.lucene90;
+
+import org.apache.lucene.codecs.DocValuesProducer;
+import org.apache.lucene.index.SegmentReadState;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.opensearch.index.codec.composite.DocValuesProvider;
+
+import java.io.IOException;
+
+/**
+ * This class is a custom abstraction of the {@link DocValuesProducer} for the Star Tree index structure.
+ * It is responsible for providing access to various types of document values (numeric, binary, sorted, sorted numeric,
+ * and sorted set) for fields in the Star Tree index.
+ *
+ * @opensearch.experimental
+ */
+public class Lucene90DocValuesProducerWrapper implements DocValuesProvider {
+
+ private final Lucene90DocValuesProducer lucene90DocValuesProducer;
+ private final SegmentReadState state;
+
+ public Lucene90DocValuesProducerWrapper(
+ SegmentReadState state,
+ String dataCodec,
+ String dataExtension,
+ String metaCodec,
+ String metaExtension
+ ) throws IOException {
+ lucene90DocValuesProducer = new Lucene90DocValuesProducer(state, dataCodec, dataExtension, metaCodec, metaExtension);
+ this.state = state;
+ }
+
+ // returns the field doc id set iterator based on field name
+ @Override
+ public SortedNumericDocValues getSortedNumeric(String fieldName) throws IOException {
+ return this.lucene90DocValuesProducer.getSortedNumeric(state.fieldInfos.fieldInfo(fieldName));
+ }
+
+ @Override
+ public DocValuesProducer getDocValuesProducer() {
+ return lucene90DocValuesProducer;
+ }
+
+}
diff --git a/server/src/main/java/org/apache/lucene/index/SortedNumericDocValuesWriterWrapper.java b/server/src/main/java/org/apache/lucene/index/SortedNumericDocValuesWriterWrapper.java
new file mode 100644
index 0000000000000..f7759fcced284
--- /dev/null
+++ b/server/src/main/java/org/apache/lucene/index/SortedNumericDocValuesWriterWrapper.java
@@ -0,0 +1,53 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.apache.lucene.index;
+
+import org.apache.lucene.util.Counter;
+
+/**
+ * A wrapper class for writing sorted numeric doc values.
+ *
+ * This class provides a convenient way to add sorted numeric doc values to a field
+ * and retrieve the corresponding {@link SortedNumericDocValues} instance.
+ *
+ * @opensearch.experimental
+ */
+public class SortedNumericDocValuesWriterWrapper {
+
+ private final SortedNumericDocValuesWriter sortedNumericDocValuesWriter;
+
+ /**
+ * Sole constructor. Constructs a new {@link SortedNumericDocValuesWriterWrapper} instance.
+ *
+ * @param fieldInfo the field information for the field being written
+ * @param counter a counter for tracking memory usage
+ */
+ public SortedNumericDocValuesWriterWrapper(FieldInfo fieldInfo, Counter counter) {
+ sortedNumericDocValuesWriter = new SortedNumericDocValuesWriter(fieldInfo, counter);
+ }
+
+ /**
+ * Adds a value to the sorted numeric doc values for the specified document.
+ *
+ * @param docID the document ID
+ * @param value the value to add
+ */
+ public void addValue(int docID, long value) {
+ sortedNumericDocValuesWriter.addValue(docID, value);
+ }
+
+ /**
+ * Returns the {@link SortedNumericDocValues} instance containing the sorted numeric doc values
+ *
+ * @return the {@link SortedNumericDocValues} instance
+ */
+ public SortedNumericDocValues getDocValues() {
+ return sortedNumericDocValuesWriter.getDocValues();
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesReader.java b/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesReader.java
deleted file mode 100644
index df5008a7f294e..0000000000000
--- a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesReader.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- */
-
-package org.opensearch.index.codec.composite;
-
-import org.apache.lucene.codecs.DocValuesProducer;
-import org.apache.lucene.index.BinaryDocValues;
-import org.apache.lucene.index.FieldInfo;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.SegmentReadState;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.lucene.index.SortedNumericDocValues;
-import org.apache.lucene.index.SortedSetDocValues;
-import org.opensearch.common.annotation.ExperimentalApi;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Reader for star tree index and star tree doc values from the segments
- *
- * @opensearch.experimental
- */
-@ExperimentalApi
-public class Composite99DocValuesReader extends DocValuesProducer implements CompositeIndexReader {
- private DocValuesProducer delegate;
-
- public Composite99DocValuesReader(DocValuesProducer producer, SegmentReadState state) throws IOException {
- this.delegate = producer;
- // TODO : read star tree files
- }
-
- @Override
- public NumericDocValues getNumeric(FieldInfo field) throws IOException {
- return delegate.getNumeric(field);
- }
-
- @Override
- public BinaryDocValues getBinary(FieldInfo field) throws IOException {
- return delegate.getBinary(field);
- }
-
- @Override
- public SortedDocValues getSorted(FieldInfo field) throws IOException {
- return delegate.getSorted(field);
- }
-
- @Override
- public SortedNumericDocValues getSortedNumeric(FieldInfo field) throws IOException {
- return delegate.getSortedNumeric(field);
- }
-
- @Override
- public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
- return delegate.getSortedSet(field);
- }
-
- @Override
- public void checkIntegrity() throws IOException {
- delegate.checkIntegrity();
- // Todo : check integrity of composite index related [star tree] files
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- // Todo: close composite index related files [star tree] files
- }
-
- @Override
- public List getCompositeIndexFields() {
- // todo : read from file formats and get the field names.
- return new ArrayList<>();
- }
-
- @Override
- public CompositeIndexValues getCompositeIndexValues(CompositeIndexFieldInfo compositeIndexFieldInfo) throws IOException {
- // TODO : read compositeIndexValues [starTreeValues] from star tree files
- throw new UnsupportedOperationException();
- }
-}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/CompositeCodecFactory.java b/server/src/main/java/org/opensearch/index/codec/composite/CompositeCodecFactory.java
index 3acedc6a27d7f..968414992c89d 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/CompositeCodecFactory.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/CompositeCodecFactory.java
@@ -12,6 +12,7 @@
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.lucene99.Lucene99Codec;
import org.opensearch.common.annotation.ExperimentalApi;
+import org.opensearch.index.codec.composite.composite99.Composite99Codec;
import org.opensearch.index.mapper.MapperService;
import java.util.HashMap;
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexReader.java b/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexReader.java
index a159b0619bcbb..9beb99e4a97cd 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexReader.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexReader.java
@@ -9,6 +9,7 @@
package org.opensearch.index.codec.composite;
import org.opensearch.common.annotation.ExperimentalApi;
+import org.opensearch.index.compositeindex.datacube.startree.index.CompositeIndexValues;
import java.io.IOException;
import java.util.List;
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/DocValuesProvider.java b/server/src/main/java/org/opensearch/index/codec/composite/DocValuesProvider.java
new file mode 100644
index 0000000000000..229ebf3b52f73
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/codec/composite/DocValuesProvider.java
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.codec.composite;
+
+import org.apache.lucene.codecs.DocValuesProducer;
+import org.apache.lucene.index.SortedNumericDocValues;
+
+import java.io.IOException;
+
+/**
+ * An interface that provides access to document values for a specific field.
+ *
+ * @opensearch.experimental
+ */
+public interface DocValuesProvider {
+
+ /**
+ * Returns the sorted numeric document values for the specified field.
+ *
+ * @param fieldName The name of the field for which to retrieve the sorted numeric document values.
+ * @return The sorted numeric document values for the specified field.
+ * @throws IOException If an error occurs while retrieving the sorted numeric document values.
+ */
+ SortedNumericDocValues getSortedNumeric(String fieldName) throws IOException;
+
+ /**
+ * Returns the DocValuesProducer instance.
+ *
+ * @return The DocValuesProducer instance.
+ */
+ DocValuesProducer getDocValuesProducer();
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesConsumerFactory.java b/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesConsumerFactory.java
new file mode 100644
index 0000000000000..a61135cfbb106
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesConsumerFactory.java
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.codec.composite;
+
+import org.apache.lucene.codecs.DocValuesConsumer;
+import org.apache.lucene.codecs.lucene90.Lucene90DocValuesConsumerWrapper;
+import org.apache.lucene.index.SegmentWriteState;
+
+import java.io.IOException;
+
+import static org.opensearch.index.codec.composite.composite99.Composite99Codec.COMPOSITE_INDEX_CODEC_NAME;
+
+/**
+ * A factory class that provides a factory method for creating {@link DocValuesConsumer} instances
+ * based on the specified composite codec.
+ *
+ * @opensearch.experimental
+ */
+public class LuceneDocValuesConsumerFactory {
+
+ public static DocValuesConsumer getDocValuesConsumerForCompositeCodec(
+ String compositeCodec,
+ SegmentWriteState state,
+ String dataCodec,
+ String dataExtension,
+ String metaCodec,
+ String metaExtension
+ ) throws IOException {
+
+ switch (compositeCodec) {
+ case COMPOSITE_INDEX_CODEC_NAME:
+ return new Lucene90DocValuesConsumerWrapper(state, dataCodec, dataExtension, metaCodec, metaExtension)
+ .getLucene90DocValuesConsumer();
+ default:
+ throw new IllegalStateException("Invalid composite codec " + "[" + compositeCodec + "]");
+ }
+
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesProducerFactory.java b/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesProducerFactory.java
new file mode 100644
index 0000000000000..a9287c610ffb1
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/codec/composite/LuceneDocValuesProducerFactory.java
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.codec.composite;
+
+import org.apache.lucene.codecs.DocValuesConsumer;
+import org.apache.lucene.codecs.lucene90.Lucene90DocValuesProducerWrapper;
+import org.apache.lucene.index.SegmentReadState;
+import org.opensearch.index.codec.composite.composite99.Composite99Codec;
+
+import java.io.IOException;
+
+/**
+ * A factory class that provides a factory method for creating {@link DocValuesConsumer} instances
+ * based on the specified composite codec.
+ *
+ * @opensearch.experimental
+ */
+public class LuceneDocValuesProducerFactory {
+
+ public static DocValuesProvider getDocValuesProducerForCompositeCodec(
+ String compositeCodec,
+ SegmentReadState state,
+ String dataCodec,
+ String dataExtension,
+ String metaCodec,
+ String metaExtension
+ ) throws IOException {
+
+ switch (compositeCodec) {
+ case Composite99Codec.COMPOSITE_INDEX_CODEC_NAME:
+ return new Lucene90DocValuesProducerWrapper(state, dataCodec, dataExtension, metaCodec, metaExtension);
+ default:
+ throw new IllegalStateException("Invalid composite codec " + "[" + compositeCodec + "]");
+ }
+
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/Composite99Codec.java b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99Codec.java
similarity index 97%
rename from server/src/main/java/org/opensearch/index/codec/composite/Composite99Codec.java
rename to server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99Codec.java
index de04944e67cd2..8422932e937c2 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/Composite99Codec.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99Codec.java
@@ -6,7 +6,7 @@
* compatible open source license.
*/
-package org.opensearch.index.codec.composite;
+package org.opensearch.index.codec.composite.composite99;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.codecs.Codec;
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesFormat.java b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesFormat.java
similarity index 61%
rename from server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesFormat.java
rename to server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesFormat.java
index 216ed4f68f333..63fe5a6af76f7 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesFormat.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesFormat.java
@@ -6,7 +6,7 @@
* compatible open source license.
*/
-package org.opensearch.index.codec.composite;
+package org.opensearch.index.codec.composite.composite99;
import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.codecs.DocValuesFormat;
@@ -37,6 +37,36 @@ public class Composite99DocValuesFormat extends DocValuesFormat {
private final DocValuesFormat delegate;
private final MapperService mapperService;
+ /** Data codec name for Composite Doc Values Format */
+ public static final String DATA_CODEC_NAME = "Composite99FormatData";
+
+ /** Meta codec name for Composite Doc Values Format */
+ public static final String META_CODEC_NAME = "Composite99FormatMeta";
+
+ /** Filename extension for the composite index data */
+ public static final String DATA_EXTENSION = "cid";
+
+ /** Filename extension for the composite index meta */
+ public static final String META_EXTENSION = "cim";
+
+ /** Data doc values codec name for Composite Doc Values Format */
+ public static final String DATA_DOC_VALUES_CODEC = "Composite99DocValuesData";
+
+ /** Meta doc values codec name for Composite Doc Values Format */
+ public static final String META_DOC_VALUES_CODEC = "Composite99DocValuesMetadata";
+
+ /** Filename extension for the composite index data doc values */
+ public static final String DATA_DOC_VALUES_EXTENSION = "cidvd";
+
+ /** Filename extension for the composite index meta doc values */
+ public static final String META_DOC_VALUES_EXTENSION = "cidvm";
+
+ /** Initial version for the Composite90DocValuesFormat */
+ public static final int VERSION_START = 0;
+
+ /** Current version for the Composite90DocValuesFormat */
+ public static final int VERSION_CURRENT = VERSION_START;
+
// needed for SPI
public Composite99DocValuesFormat() {
this(new Lucene90DocValuesFormat(), null);
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesReader.java b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesReader.java
new file mode 100644
index 0000000000000..4fb15d15d1bbe
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesReader.java
@@ -0,0 +1,298 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.codec.composite.composite99;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.codecs.CodecUtil;
+import org.apache.lucene.codecs.DocValuesProducer;
+import org.apache.lucene.index.BinaryDocValues;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.DocValues;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.FieldInfos;
+import org.apache.lucene.index.IndexFileNames;
+import org.apache.lucene.index.NumericDocValues;
+import org.apache.lucene.index.SegmentReadState;
+import org.apache.lucene.index.SortedDocValues;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.index.SortedSetDocValues;
+import org.apache.lucene.store.ChecksumIndexInput;
+import org.apache.lucene.store.IndexInput;
+import org.opensearch.common.annotation.ExperimentalApi;
+import org.opensearch.common.util.io.IOUtils;
+import org.opensearch.index.codec.composite.CompositeIndexFieldInfo;
+import org.opensearch.index.codec.composite.CompositeIndexReader;
+import org.opensearch.index.codec.composite.DocValuesProvider;
+import org.opensearch.index.codec.composite.LuceneDocValuesProducerFactory;
+import org.opensearch.index.compositeindex.CompositeIndexMetadata;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.MetricEntry;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.StarTreeMetadata;
+import org.opensearch.index.compositeindex.datacube.startree.index.CompositeIndexValues;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
+import org.opensearch.index.mapper.CompositeMappedFieldType;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.COMPOSITE_FIELD_MARKER;
+import static org.opensearch.index.compositeindex.datacube.startree.fileformats.StarTreeWriter.VERSION_CURRENT;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeDimensionsDocValues;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeMetricsDocValues;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.getFieldInfoList;
+
+/**
+ * Reader for star tree index and star tree doc values from the segments
+ *
+ * @opensearch.experimental
+ */
+@ExperimentalApi
+public class Composite99DocValuesReader extends DocValuesProducer implements CompositeIndexReader {
+ private static final Logger logger = LogManager.getLogger(Composite99DocValuesReader.class);
+
+ private final DocValuesProducer delegate;
+ private IndexInput dataIn;
+ private ChecksumIndexInput metaIn;
+ private final Map compositeIndexInputMap = new LinkedHashMap<>();
+ private final Map compositeIndexMetadataMap = new LinkedHashMap<>();
+ private final List fields;
+ private DocValuesProvider compositeDocValuesProducer;
+ private final List compositeFieldInfos = new ArrayList<>();
+ private final SegmentReadState readState;
+
+ public Composite99DocValuesReader(DocValuesProducer producer, SegmentReadState readState) throws IOException {
+ this.delegate = producer;
+ this.readState = readState;
+ this.fields = new ArrayList<>();
+
+ String metaFileName = IndexFileNames.segmentFileName(
+ readState.segmentInfo.name,
+ readState.segmentSuffix,
+ Composite99DocValuesFormat.META_EXTENSION
+ );
+
+ String dataFileName = IndexFileNames.segmentFileName(
+ readState.segmentInfo.name,
+ readState.segmentSuffix,
+ Composite99DocValuesFormat.DATA_EXTENSION
+ );
+
+ boolean success = false;
+ try {
+
+ // initialize meta input
+ dataIn = readState.directory.openInput(dataFileName, readState.context);
+ CodecUtil.checkIndexHeader(
+ dataIn,
+ Composite99DocValuesFormat.DATA_CODEC_NAME,
+ Composite99DocValuesFormat.VERSION_START,
+ Composite99DocValuesFormat.VERSION_CURRENT,
+ readState.segmentInfo.getId(),
+ readState.segmentSuffix
+ );
+
+ // initialize data input
+ metaIn = readState.directory.openChecksumInput(metaFileName, readState.context);
+ Throwable priorE = null;
+ try {
+ CodecUtil.checkIndexHeader(
+ metaIn,
+ Composite99DocValuesFormat.META_CODEC_NAME,
+ Composite99DocValuesFormat.VERSION_START,
+ Composite99DocValuesFormat.VERSION_CURRENT,
+ readState.segmentInfo.getId(),
+ readState.segmentSuffix
+ );
+
+ while (true) {
+
+ // validate magic marker
+ long magicMarker = metaIn.readLong();
+ if (magicMarker == -1) {
+ logger.info("EOF reached for composite index metadata");
+ break;
+ } else if (magicMarker < 0) {
+ throw new CorruptIndexException("Unknown token encountered: " + magicMarker, metaIn);
+ } else if (COMPOSITE_FIELD_MARKER != magicMarker) {
+ logger.error("Invalid composite field magic marker");
+ throw new IOException("Invalid composite field magic marker");
+ }
+
+ int version = metaIn.readVInt();
+ if (VERSION_CURRENT != version) {
+ logger.error("Invalid composite field version");
+ throw new IOException("Invalid composite field version");
+ }
+
+ // construct composite index metadata
+ String compositeFieldName = metaIn.readString();
+ CompositeMappedFieldType.CompositeFieldType compositeFieldType = CompositeMappedFieldType.CompositeFieldType.fromName(
+ metaIn.readString()
+ );
+
+ switch (compositeFieldType) {
+ case STAR_TREE:
+ StarTreeMetadata starTreeMetadata = new StarTreeMetadata(metaIn, compositeFieldName, compositeFieldType);
+ compositeFieldInfos.add(new CompositeIndexFieldInfo(compositeFieldName, compositeFieldType));
+
+ IndexInput starTreeIndexInput = dataIn.slice(
+ "star-tree data slice for respective star-tree fields",
+ starTreeMetadata.getDataStartFilePointer(),
+ starTreeMetadata.getDataLength()
+ );
+ compositeIndexInputMap.put(compositeFieldName, starTreeIndexInput);
+ compositeIndexMetadataMap.put(compositeFieldName, starTreeMetadata);
+
+ List dimensionFields = starTreeMetadata.getDimensionFields();
+
+ // generating star tree unique fields (fully qualified name for dimension and metrics)
+ for (String dimensions : dimensionFields) {
+ fields.add(fullyQualifiedFieldNameForStarTreeDimensionsDocValues(compositeFieldName, dimensions));
+ }
+
+ for (MetricEntry metricEntry : starTreeMetadata.getMetricEntries()) {
+ fields.add(
+ fullyQualifiedFieldNameForStarTreeMetricsDocValues(
+ compositeFieldName,
+ metricEntry.getMetricFieldName(),
+ metricEntry.getMetricStat().getTypeName()
+ )
+ );
+ }
+
+ break;
+ default:
+ throw new CorruptIndexException("Invalid composite field type found in the file", dataIn);
+ }
+ }
+
+ // populates the dummy list of field infos to fetch doc id set iterators for respective fields.
+ // the dummy field info is used to fetch the doc id set iterators for respective fields based on field name
+ FieldInfos fieldInfos = new FieldInfos(getFieldInfoList(fields));
+ SegmentReadState segmentReadState = new SegmentReadState(
+ readState.directory,
+ readState.segmentInfo,
+ fieldInfos,
+ readState.context
+ );
+
+ // initialize star-tree doc values producer
+
+ compositeDocValuesProducer = LuceneDocValuesProducerFactory.getDocValuesProducerForCompositeCodec(
+ Composite99Codec.COMPOSITE_INDEX_CODEC_NAME,
+ segmentReadState,
+ Composite99DocValuesFormat.DATA_DOC_VALUES_CODEC,
+ Composite99DocValuesFormat.DATA_DOC_VALUES_EXTENSION,
+ Composite99DocValuesFormat.META_DOC_VALUES_CODEC,
+ Composite99DocValuesFormat.META_DOC_VALUES_EXTENSION
+ );
+
+ } catch (Throwable t) {
+ priorE = t;
+ } finally {
+ CodecUtil.checkFooter(metaIn, priorE);
+ }
+ success = true;
+ } finally {
+ if (success == false) {
+ IOUtils.closeWhileHandlingException(this);
+ }
+ }
+ }
+
+ @Override
+ public NumericDocValues getNumeric(FieldInfo field) throws IOException {
+ return delegate.getNumeric(field);
+ }
+
+ @Override
+ public BinaryDocValues getBinary(FieldInfo field) throws IOException {
+ return delegate.getBinary(field);
+ }
+
+ @Override
+ public SortedDocValues getSorted(FieldInfo field) throws IOException {
+ return delegate.getSorted(field);
+ }
+
+ @Override
+ public SortedNumericDocValues getSortedNumeric(FieldInfo field) throws IOException {
+ return delegate.getSortedNumeric(field);
+ }
+
+ @Override
+ public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
+ return delegate.getSortedSet(field);
+ }
+
+ @Override
+ public void checkIntegrity() throws IOException {
+ delegate.checkIntegrity();
+ CodecUtil.checksumEntireFile(dataIn);
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ boolean success = false;
+ try {
+ IOUtils.close(metaIn, dataIn);
+ IOUtils.close(compositeDocValuesProducer.getDocValuesProducer());
+ success = true;
+ } finally {
+ if (!success) {
+ IOUtils.closeWhileHandlingException(metaIn, dataIn);
+ }
+ compositeIndexInputMap.clear();
+ compositeIndexMetadataMap.clear();
+ fields.clear();
+ metaIn = null;
+ dataIn = null;
+ }
+ }
+
+ @Override
+ public List getCompositeIndexFields() {
+ return compositeFieldInfos;
+ }
+
+ @Override
+ public CompositeIndexValues getCompositeIndexValues(CompositeIndexFieldInfo compositeIndexFieldInfo) throws IOException {
+
+ switch (compositeIndexFieldInfo.getType()) {
+ case STAR_TREE:
+ return new StarTreeValues(
+ compositeIndexMetadataMap.get(compositeIndexFieldInfo.getField()),
+ compositeIndexInputMap.get(compositeIndexFieldInfo.getField()),
+ compositeDocValuesProducer
+ );
+
+ default:
+ throw new CorruptIndexException("Unsupported composite index field type: ", compositeIndexFieldInfo.getType().getName());
+ }
+
+ }
+
+ /**
+ * Returns the sorted numeric doc values for the given sorted numeric field.
+ * If the sorted numeric field is null, it returns an empty doc id set iterator.
+ *
+ * Sorted numeric field can be null for cases where the segment doesn't hold a particular value.
+ *
+ * @param sortedNumeric the sorted numeric doc values for a field
+ * @return empty sorted numeric values if the field is not present, else sortedNumeric
+ */
+ public static SortedNumericDocValues getSortedNumericDocValues(SortedNumericDocValues sortedNumeric) {
+ return sortedNumeric == null ? DocValues.emptySortedNumeric() : sortedNumeric;
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesWriter.java b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesWriter.java
similarity index 67%
rename from server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesWriter.java
rename to server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesWriter.java
index 6ed1a8c42e380..c0bde4388c241 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/Composite99DocValuesWriter.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/composite99/Composite99DocValuesWriter.java
@@ -6,25 +6,35 @@
* compatible open source license.
*/
-package org.opensearch.index.codec.composite;
+package org.opensearch.index.codec.composite.composite99;
+import org.apache.lucene.codecs.CodecUtil;
import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.codecs.DocValuesProducer;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.EmptyDocValuesProducer;
import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.IndexFileNames;
import org.apache.lucene.index.MergeState;
import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.store.IndexOutput;
import org.opensearch.common.annotation.ExperimentalApi;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
+import org.opensearch.common.util.io.IOUtils;
+import org.opensearch.index.codec.composite.CompositeIndexFieldInfo;
+import org.opensearch.index.codec.composite.CompositeIndexReader;
+import org.opensearch.index.codec.composite.LuceneDocValuesConsumerFactory;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
import org.opensearch.index.compositeindex.datacube.startree.builder.StarTreesBuilder;
+import org.opensearch.index.compositeindex.datacube.startree.index.CompositeIndexValues;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import org.opensearch.index.mapper.CompositeMappedFieldType;
import org.opensearch.index.mapper.MapperService;
+import org.opensearch.index.mapper.StarTreeMapper;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -47,12 +57,17 @@ public class Composite99DocValuesWriter extends DocValuesConsumer {
AtomicReference mergeState = new AtomicReference<>();
private final Set compositeMappedFieldTypes;
private final Set compositeFieldSet;
+ private DocValuesConsumer composite99DocValuesConsumer;
+
+ public IndexOutput dataOut;
+ public IndexOutput metaOut;
private final Set segmentFieldSet;
private final boolean segmentHasCompositeFields;
private final Map fieldProducerMap = new HashMap<>();
- public Composite99DocValuesWriter(DocValuesConsumer delegate, SegmentWriteState segmentWriteState, MapperService mapperService) {
+ public Composite99DocValuesWriter(DocValuesConsumer delegate, SegmentWriteState segmentWriteState, MapperService mapperService)
+ throws IOException {
this.delegate = delegate;
this.state = segmentWriteState;
@@ -68,6 +83,52 @@ public Composite99DocValuesWriter(DocValuesConsumer delegate, SegmentWriteState
for (CompositeMappedFieldType type : compositeMappedFieldTypes) {
compositeFieldSet.addAll(type.fields());
}
+
+ boolean success = false;
+ try {
+ this.composite99DocValuesConsumer = LuceneDocValuesConsumerFactory.getDocValuesConsumerForCompositeCodec(
+ Composite99Codec.COMPOSITE_INDEX_CODEC_NAME,
+ segmentWriteState,
+ Composite99DocValuesFormat.DATA_DOC_VALUES_CODEC,
+ Composite99DocValuesFormat.DATA_DOC_VALUES_EXTENSION,
+ Composite99DocValuesFormat.META_DOC_VALUES_CODEC,
+ Composite99DocValuesFormat.META_DOC_VALUES_EXTENSION
+ );
+
+ String dataFileName = IndexFileNames.segmentFileName(
+ segmentWriteState.segmentInfo.name,
+ segmentWriteState.segmentSuffix,
+ Composite99DocValuesFormat.DATA_EXTENSION
+ );
+ dataOut = segmentWriteState.directory.createOutput(dataFileName, segmentWriteState.context);
+ CodecUtil.writeIndexHeader(
+ dataOut,
+ Composite99DocValuesFormat.DATA_CODEC_NAME,
+ Composite99DocValuesFormat.VERSION_CURRENT,
+ segmentWriteState.segmentInfo.getId(),
+ segmentWriteState.segmentSuffix
+ );
+
+ String metaFileName = IndexFileNames.segmentFileName(
+ segmentWriteState.segmentInfo.name,
+ segmentWriteState.segmentSuffix,
+ Composite99DocValuesFormat.META_EXTENSION
+ );
+ metaOut = segmentWriteState.directory.createOutput(metaFileName, segmentWriteState.context);
+ CodecUtil.writeIndexHeader(
+ metaOut,
+ Composite99DocValuesFormat.META_CODEC_NAME,
+ Composite99DocValuesFormat.VERSION_CURRENT,
+ segmentWriteState.segmentInfo.getId(),
+ segmentWriteState.segmentSuffix
+ );
+
+ success = true;
+ } finally {
+ if (success == false) {
+ IOUtils.closeWhileHandlingException(this);
+ }
+ }
// check if there are any composite fields which are part of the segment
segmentHasCompositeFields = Collections.disjoint(segmentFieldSet, compositeFieldSet) == false;
}
@@ -104,6 +165,26 @@ public void addSortedSetField(FieldInfo field, DocValuesProducer valuesProducer)
@Override
public void close() throws IOException {
delegate.close();
+ boolean success = false;
+ try {
+ if (metaOut != null) {
+ metaOut.writeLong(-1); // write EOF marker
+ CodecUtil.writeFooter(metaOut); // write checksum
+ }
+ if (dataOut != null) {
+ CodecUtil.writeFooter(dataOut); // write checksum
+ }
+
+ success = true;
+ } finally {
+ if (success) {
+ IOUtils.close(dataOut, metaOut, composite99DocValuesConsumer);
+ } else {
+ IOUtils.closeWhileHandlingException(dataOut, metaOut, composite99DocValuesConsumer);
+ }
+ metaOut = dataOut = null;
+ composite99DocValuesConsumer = null;
+ }
}
private void createCompositeIndicesIfPossible(DocValuesProducer valuesProducer, FieldInfo field) throws IOException {
@@ -128,9 +209,9 @@ public SortedNumericDocValues getSortedNumeric(FieldInfo field) {
// we have all the required fields to build composite fields
if (compositeFieldSet.isEmpty()) {
for (CompositeMappedFieldType mappedType : compositeMappedFieldTypes) {
- if (mappedType.getCompositeIndexType().equals(CompositeMappedFieldType.CompositeFieldType.STAR_TREE)) {
+ if (mappedType instanceof StarTreeMapper.StarTreeFieldType) {
try (StarTreesBuilder starTreesBuilder = new StarTreesBuilder(state, mapperService)) {
- starTreesBuilder.build(fieldProducerMap);
+ starTreesBuilder.build(metaOut, dataOut, fieldProducerMap, composite99DocValuesConsumer);
}
}
}
@@ -147,6 +228,7 @@ public void merge(MergeState mergeState) throws IOException {
/**
* Merges composite fields from multiple segments
+ *
* @param mergeState merge state
*/
private void mergeCompositeFields(MergeState mergeState) throws IOException {
@@ -155,6 +237,7 @@ private void mergeCompositeFields(MergeState mergeState) throws IOException {
/**
* Merges star tree data fields from multiple segments
+ *
* @param mergeState merge state
*/
private void mergeStarTreeFields(MergeState mergeState) throws IOException {
@@ -177,7 +260,7 @@ private void mergeStarTreeFields(MergeState mergeState) throws IOException {
CompositeIndexValues compositeIndexValues = reader.getCompositeIndexValues(fieldInfo);
if (compositeIndexValues instanceof StarTreeValues) {
StarTreeValues starTreeValues = (StarTreeValues) compositeIndexValues;
- List fieldsList = starTreeSubsPerField.getOrDefault(fieldInfo.getField(), Collections.emptyList());
+ List fieldsList = starTreeSubsPerField.getOrDefault(fieldInfo.getField(), new ArrayList<>());
if (starTreeField == null) {
starTreeField = starTreeValues.getStarTreeField();
}
@@ -196,7 +279,7 @@ private void mergeStarTreeFields(MergeState mergeState) throws IOException {
}
}
try (StarTreesBuilder starTreesBuilder = new StarTreesBuilder(state, mapperService)) {
- starTreesBuilder.buildDuringMerge(starTreeSubsPerField);
+ starTreesBuilder.buildDuringMerge(metaOut, dataOut, starTreeSubsPerField, composite99DocValuesConsumer);
}
}
}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/composite99/package-info.java b/server/src/main/java/org/opensearch/index/codec/composite/composite99/package-info.java
new file mode 100644
index 0000000000000..3d6f130b9a7c8
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/codec/composite/composite99/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/**
+ * Responsible for handling all composite index codecs and operations associated with Composite99 codec
+ */
+package org.opensearch.index.codec.composite.composite99;
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeValues.java b/server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeValues.java
deleted file mode 100644
index 8378a4063b7ca..0000000000000
--- a/server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeValues.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- */
-
-package org.opensearch.index.codec.composite.datacube.startree;
-
-import org.apache.lucene.search.DocIdSetIterator;
-import org.opensearch.common.annotation.ExperimentalApi;
-import org.opensearch.index.codec.composite.CompositeIndexValues;
-import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
-import org.opensearch.index.compositeindex.datacube.startree.node.StarTreeNode;
-
-import java.util.Map;
-
-/**
- * Concrete class that holds the star tree associated values from the segment
- *
- * @opensearch.experimental
- */
-@ExperimentalApi
-public class StarTreeValues implements CompositeIndexValues {
- private final StarTreeField starTreeField;
- private final StarTreeNode root;
- private final Map dimensionDocValuesIteratorMap;
- private final Map metricDocValuesIteratorMap;
- private final Map attributes;
-
- public StarTreeValues(
- StarTreeField starTreeField,
- StarTreeNode root,
- Map dimensionDocValuesIteratorMap,
- Map metricDocValuesIteratorMap,
- Map attributes
- ) {
- this.starTreeField = starTreeField;
- this.root = root;
- this.dimensionDocValuesIteratorMap = dimensionDocValuesIteratorMap;
- this.metricDocValuesIteratorMap = metricDocValuesIteratorMap;
- this.attributes = attributes;
- }
-
- @Override
- public CompositeIndexValues getValues() {
- return this;
- }
-
- public StarTreeField getStarTreeField() {
- return starTreeField;
- }
-
- public StarTreeNode getRoot() {
- return root;
- }
-
- public Map getDimensionDocValuesIteratorMap() {
- return dimensionDocValuesIteratorMap;
- }
-
- public Map getMetricDocValuesIteratorMap() {
- return metricDocValuesIteratorMap;
- }
-
- public Map getAttributes() {
- return attributes;
- }
-}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/package-info.java b/server/src/main/java/org/opensearch/index/codec/composite/package-info.java
index 5d15e99c00975..2b25ee4428c5c 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/package-info.java
+++ b/server/src/main/java/org/opensearch/index/codec/composite/package-info.java
@@ -7,6 +7,6 @@
*/
/**
- * classes responsible for handling all composite index codecs and operations
+ * Responsible for handling all composite index codecs and operations
*/
package org.opensearch.index.codec.composite;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexConstants.java b/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexConstants.java
new file mode 100644
index 0000000000000..ffa3dee3578e5
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexConstants.java
@@ -0,0 +1,26 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex;
+
+/**
+ * This class contains constants used in the Composite Index implementation.
+ */
+public class CompositeIndexConstants {
+
+ /**
+ * The magic marker value used for sanity checks in the Composite Index implementation.
+ */
+ public static final long COMPOSITE_FIELD_MARKER = 0xC0950513F1E1DL; // Composite Field
+
+ /**
+ * Represents the key to fetch number of documents in a segment.
+ */
+ public static final String SEGMENT_DOCS_COUNT = "segmentDocsCount";
+
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexMetadata.java b/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexMetadata.java
new file mode 100644
index 0000000000000..6ba401afe0e6f
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/CompositeIndexMetadata.java
@@ -0,0 +1,53 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex;
+
+import org.opensearch.index.mapper.CompositeMappedFieldType;
+
+/**
+ * This class represents the metadata of a Composite Index, which includes information about
+ * the composite field name, type, and the specific metadata for the type of composite field
+ * (e.g., Tree metadata).
+ *
+ * @opensearch.experimental
+ */
+public class CompositeIndexMetadata {
+
+ private final String compositeFieldName;
+ private final CompositeMappedFieldType.CompositeFieldType compositeFieldType;
+
+ /**
+ * Constructs a CompositeIndexMetadata object with the provided composite field name and type.
+ *
+ * @param compositeFieldName the name of the composite field
+ * @param compositeFieldType the type of the composite field
+ */
+ public CompositeIndexMetadata(String compositeFieldName, CompositeMappedFieldType.CompositeFieldType compositeFieldType) {
+ this.compositeFieldName = compositeFieldName;
+ this.compositeFieldType = compositeFieldType;
+ }
+
+ /**
+ * Returns the name of the composite field.
+ *
+ * @return the composite field name
+ */
+ public String getCompositeFieldName() {
+ return compositeFieldName;
+ }
+
+ /**
+ * Returns the type of the composite field.
+ *
+ * @return the composite field type
+ */
+ public CompositeMappedFieldType.CompositeFieldType getCompositeFieldType() {
+ return compositeFieldType;
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/MetricStat.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/MetricStat.java
index fbde296b15f7e..632f8de21d26d 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/MetricStat.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/MetricStat.java
@@ -17,22 +17,28 @@
*/
@ExperimentalApi
public enum MetricStat {
- COUNT("count"),
- AVG("avg"),
- SUM("sum"),
- MIN("min"),
- MAX("max");
+ COUNT("count", 0),
+ AVG("avg", 1),
+ SUM("sum", 2),
+ MIN("min", 3),
+ MAX("max", 4);
private final String typeName;
+ private final int metricOrdinal;
- MetricStat(String typeName) {
+ MetricStat(String typeName, int metricOrdinal) {
this.typeName = typeName;
+ this.metricOrdinal = metricOrdinal;
}
public String getTypeName() {
return typeName;
}
+ public int getMetricOrdinal() {
+ return metricOrdinal;
+ }
+
public static MetricStat fromTypeName(String typeName) {
for (MetricStat metric : MetricStat.values()) {
if (metric.getTypeName().equalsIgnoreCase(typeName)) {
@@ -41,4 +47,13 @@ public static MetricStat fromTypeName(String typeName) {
}
throw new IllegalArgumentException("Invalid metric stat: " + typeName);
}
+
+ public static MetricStat fromMetricOrdinal(int metricOrdinal) {
+ for (MetricStat metric : MetricStat.values()) {
+ if (metric.getMetricOrdinal() == metricOrdinal) {
+ return metric;
+ }
+ }
+ throw new IllegalArgumentException("Invalid metric stat: " + metricOrdinal);
+ }
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/ReadDimension.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/ReadDimension.java
new file mode 100644
index 0000000000000..5b6a20b8d1078
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/ReadDimension.java
@@ -0,0 +1,56 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube;
+
+import org.opensearch.core.xcontent.ToXContent;
+import org.opensearch.core.xcontent.XContentBuilder;
+import org.opensearch.index.mapper.CompositeDataCubeFieldType;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Composite index merge dimension class
+ *
+ * @opensearch.experimental
+ */
+public class ReadDimension implements Dimension {
+ public static final String READ = "read";
+ private final String field;
+
+ public ReadDimension(String field) {
+ this.field = field;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
+ builder.startObject();
+ builder.field(CompositeDataCubeFieldType.NAME, field);
+ builder.field(CompositeDataCubeFieldType.TYPE, READ);
+ builder.endObject();
+ return builder;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ReadDimension dimension = (ReadDimension) o;
+ return Objects.equals(field, dimension.getField());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(field);
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/StarTreeFieldConfiguration.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/StarTreeFieldConfiguration.java
index 755c064c2c60a..d732a8598d711 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/StarTreeFieldConfiguration.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/StarTreeFieldConfiguration.java
@@ -56,19 +56,25 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
@ExperimentalApi
public enum StarTreeBuildMode {
// TODO : remove onheap support unless this proves useful
- ON_HEAP("onheap"),
- OFF_HEAP("offheap");
+ ON_HEAP("onheap", (byte) 0),
+ OFF_HEAP("offheap", (byte) 1);
private final String typeName;
+ private final byte buildModeOrdinal;
- StarTreeBuildMode(String typeName) {
+ StarTreeBuildMode(String typeName, byte buildModeOrdinal) {
this.typeName = typeName;
+ this.buildModeOrdinal = buildModeOrdinal;
}
public String getTypeName() {
return typeName;
}
+ public byte getBuildModeOrdinal() {
+ return buildModeOrdinal;
+ }
+
public static StarTreeBuildMode fromTypeName(String typeName) {
for (StarTreeBuildMode starTreeBuildMode : StarTreeBuildMode.values()) {
if (starTreeBuildMode.getTypeName().equalsIgnoreCase(typeName)) {
@@ -77,6 +83,16 @@ public static StarTreeBuildMode fromTypeName(String typeName) {
}
throw new IllegalArgumentException(String.format(Locale.ROOT, "Invalid star tree build mode: [%s] ", typeName));
}
+
+ public static StarTreeBuildMode fromBuildModeOrdinal(byte buildModeOrdinal) {
+ for (StarTreeBuildMode starTreeBuildMode : StarTreeBuildMode.values()) {
+ if (starTreeBuildMode.getBuildModeOrdinal() == buildModeOrdinal) {
+ return starTreeBuildMode;
+ }
+ }
+ throw new IllegalArgumentException(String.format(Locale.ROOT, "Invalid star tree build mode: [%s] ", buildModeOrdinal));
+ }
+
}
public int maxLeafDocs() {
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/StatelessDoubleValueAggregator.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/StatelessDoubleValueAggregator.java
index 04c6bcc906ef2..27191847068a9 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/StatelessDoubleValueAggregator.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/StatelessDoubleValueAggregator.java
@@ -57,7 +57,7 @@ public Double toStarTreeNumericTypeValue(Long value) {
if (value == null) {
return getIdentityMetricValue();
}
- return starTreeNumericType.getDoubleValue(value);
+ return VALUE_AGGREGATOR_TYPE.getDoubleValue(value);
} catch (Exception e) {
throw new IllegalStateException("Cannot convert " + value + " to sortable aggregation type", e);
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/SumValueAggregator.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/SumValueAggregator.java
index 1568debd91ae7..362a6e16563fb 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/SumValueAggregator.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/aggregators/SumValueAggregator.java
@@ -67,7 +67,11 @@ public Double mergeAggregatedValues(Double value, Double aggregatedValue) {
assert aggregatedValue == null || kahanSummation.value() == aggregatedValue;
// add takes care of the sum and compensation internally
if (value != null) {
- kahanSummation.add(value);
+ if (value != null) {
+ kahanSummation.add(value);
+ } else {
+ kahanSummation.add(getIdentityMetricValue());
+ }
} else {
kahanSummation.add(getIdentityMetricValue());
}
@@ -92,7 +96,7 @@ public Double toStarTreeNumericTypeValue(Long value) {
if (value == null) {
return getIdentityMetricValue();
}
- return starTreeNumericType.getDoubleValue(value);
+ return VALUE_AGGREGATOR_TYPE.getDoubleValue(value);
} catch (Exception e) {
throw new IllegalStateException("Cannot convert " + value + " to sortable aggregation type", e);
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/BaseStarTreeBuilder.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/BaseStarTreeBuilder.java
index 872826aa6db06..3c45f0b200b10 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/BaseStarTreeBuilder.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/BaseStarTreeBuilder.java
@@ -9,14 +9,16 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.codecs.DocValuesProducer;
-import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.EmptyDocValuesProducer;
import org.apache.lucene.index.FieldInfo;
-import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.SegmentWriteState;
-import org.apache.lucene.index.VectorEncoding;
-import org.apache.lucene.index.VectorSimilarityFunction;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
+import org.apache.lucene.index.SortedNumericDocValues;
+import org.apache.lucene.index.SortedNumericDocValuesWriterWrapper;
+import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.util.Counter;
+import org.apache.lucene.util.NumericUtils;
import org.opensearch.index.compositeindex.datacube.Dimension;
import org.opensearch.index.compositeindex.datacube.Metric;
import org.opensearch.index.compositeindex.datacube.MetricStat;
@@ -25,8 +27,12 @@
import org.opensearch.index.compositeindex.datacube.startree.StarTreeFieldConfiguration;
import org.opensearch.index.compositeindex.datacube.startree.aggregators.MetricAggregatorInfo;
import org.opensearch.index.compositeindex.datacube.startree.aggregators.ValueAggregator;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.StarTreeWriter;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
+import org.opensearch.index.compositeindex.datacube.startree.node.InMemoryTreeNode;
+import org.opensearch.index.compositeindex.datacube.startree.node.StarTreeNodeType;
import org.opensearch.index.compositeindex.datacube.startree.utils.SequentialDocValuesIterator;
-import org.opensearch.index.compositeindex.datacube.startree.utils.TreeNode;
+import org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils;
import org.opensearch.index.fielddata.IndexNumericFieldData;
import org.opensearch.index.mapper.Mapper;
import org.opensearch.index.mapper.MapperService;
@@ -35,7 +41,6 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -43,8 +48,11 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
-import static org.opensearch.index.compositeindex.datacube.startree.utils.TreeNode.ALL;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.ALL;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeDimensionsDocValues;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeMetricsDocValues;
/**
* Builder for star tree. Defines the algorithm to construct star-tree
@@ -70,22 +78,33 @@ public abstract class BaseStarTreeBuilder implements StarTreeBuilder {
protected int numStarTreeNodes;
protected final int maxLeafDocuments;
- protected final TreeNode rootNode = getNewNode();
+ protected final InMemoryTreeNode rootNode = getNewNode();
protected final StarTreeField starTreeField;
- private final SegmentWriteState state;
- static String NUM_SEGMENT_DOCS = "numSegmentDocs";
+ private final SegmentWriteState writeState;
+
+ private final IndexOutput metaOut;
+ private final IndexOutput dataOut;
/**
* Reads all the configuration related to dimensions and metrics, builds a star-tree based on the different construction parameters.
*
* @param starTreeField holds the configuration for the star tree
- * @param state stores the segment write state
+ * @param writeState stores the segment write writeState
* @param mapperService helps to find the original type of the field
*/
- protected BaseStarTreeBuilder(StarTreeField starTreeField, SegmentWriteState state, MapperService mapperService) {
+ protected BaseStarTreeBuilder(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ StarTreeField starTreeField,
+ SegmentWriteState writeState,
+ MapperService mapperService
+ ) {
logger.debug("Building star tree : {}", starTreeField.getName());
+ this.metaOut = metaOut;
+ this.dataOut = dataOut;
+
this.starTreeField = starTreeField;
StarTreeFieldConfiguration starTreeFieldSpec = starTreeField.getStarTreeConfig();
@@ -93,8 +112,8 @@ protected BaseStarTreeBuilder(StarTreeField starTreeField, SegmentWriteState sta
this.numDimensions = dimensionsSplitOrder.size();
this.skipStarNodeCreationForDimensions = new HashSet<>();
- this.totalSegmentDocs = state.segmentInfo.maxDoc();
- this.state = state;
+ this.totalSegmentDocs = writeState.segmentInfo.maxDoc();
+ this.writeState = writeState;
Set skipStarNodeCreationForDimensions = starTreeFieldSpec.getSkipStarNodeCreationInDims();
@@ -139,6 +158,223 @@ public List generateMetricAggregatorInfos(MapperService ma
return metricAggregatorInfos;
}
+ /**
+ * Generates the configuration required to perform aggregation for all the metrics on a field
+ *
+ * @return list of MetricAggregatorInfo
+ */
+ public List getMetricReaders(SegmentWriteState state, Map fieldProducerMap)
+ throws IOException {
+
+ List metricReaders = new ArrayList<>();
+ for (Metric metric : this.starTreeField.getMetrics()) {
+ for (MetricStat metricStat : metric.getMetrics()) {
+ SequentialDocValuesIterator metricReader;
+ FieldInfo metricFieldInfo = state.fieldInfos.fieldInfo(metric.getField());
+ // if (metricStat != MetricStat.COUNT) {
+ if (metricFieldInfo == null) {
+ metricFieldInfo = StarTreeUtils.getFieldInfo(metric.getField(), 1);
+ }
+ metricReader = new SequentialDocValuesIterator(
+ fieldProducerMap.get(metricFieldInfo.name).getSortedNumeric(metricFieldInfo)
+ );
+ // } else {
+ // metricReader = new SequentialDocValuesIterator();
+ // }
+
+ metricReaders.add(metricReader);
+ }
+ }
+ return metricReaders;
+ }
+
+ /**
+ * Builds the star tree from the original segment documents
+ *
+ * @param fieldProducerMap contain s the docValues producer to get docValues associated with each field
+ * @param fieldNumberAcrossStarTrees maintains a counter for the number of star-tree fields
+ * @param starTreeDocValuesConsumer consumes the generated star-tree docValues
+ * @throws IOException when we are unable to build star-tree
+ */
+ public void build(
+ Map fieldProducerMap,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
+ long startTime = System.currentTimeMillis();
+ logger.debug("Star-tree build is a go with star tree field {}", starTreeField.getName());
+
+ List metricReaders = getMetricReaders(writeState, fieldProducerMap);
+ List dimensionsSplitOrder = starTreeField.getDimensionsOrder();
+ SequentialDocValuesIterator[] dimensionReaders = new SequentialDocValuesIterator[dimensionsSplitOrder.size()];
+ for (int i = 0; i < numDimensions; i++) {
+ String dimension = dimensionsSplitOrder.get(i).getField();
+ FieldInfo dimensionFieldInfo = writeState.fieldInfos.fieldInfo(dimension);
+ if (dimensionFieldInfo == null) {
+ dimensionFieldInfo = StarTreeUtils.getFieldInfo(dimension, 0);
+ }
+ dimensionReaders[i] = new SequentialDocValuesIterator(
+ fieldProducerMap.get(dimensionFieldInfo.name).getSortedNumeric(dimensionFieldInfo)
+ );
+ }
+ Iterator starTreeDocumentIterator = sortAndAggregateSegmentDocuments(dimensionReaders, metricReaders);
+ logger.debug("Sorting and aggregating star-tree in ms : {}", (System.currentTimeMillis() - startTime));
+ build(starTreeDocumentIterator, fieldNumberAcrossStarTrees, starTreeDocValuesConsumer);
+ logger.debug("Finished Building star-tree in ms : {}", (System.currentTimeMillis() - startTime));
+ }
+
+ /**
+ * Builds the star tree using sorted and aggregated star-tree Documents
+ *
+ * @param starTreeDocumentIterator contains the sorted and aggregated documents
+ * @param fieldNumberAcrossStarTrees maintains a counter for the number of star-tree fields
+ * @param starTreeDocValuesConsumer consumes the generated star-tree docValues
+ * @throws IOException when we are unable to build star-tree
+ */
+ public void build(
+ Iterator starTreeDocumentIterator,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
+ int numSegmentStarTreeDocument = totalSegmentDocs;
+
+ appendDocumentsToStarTree(starTreeDocumentIterator);
+ int numStarTreeDocument = numStarTreeDocs;
+ logger.debug("Generated star tree docs : [{}] from segment docs : [{}]", numStarTreeDocument, numSegmentStarTreeDocument);
+
+ if (numStarTreeDocs == 0) {
+ // serialize the star tree data
+ serializeStarTree(numStarTreeDocument);
+ return;
+ }
+
+ constructStarTree(rootNode, 0, numStarTreeDocs);
+ int numStarTreeDocumentUnderStarNode = numStarTreeDocs - numStarTreeDocument;
+ logger.debug(
+ "Finished constructing star-tree, got [ {} ] tree nodes and [ {} ] starTreeDocument under star-node",
+ numStarTreeNodes,
+ numStarTreeDocumentUnderStarNode
+ );
+
+ createAggregatedDocs(rootNode);
+ int numAggregatedStarTreeDocument = numStarTreeDocs - numStarTreeDocument - numStarTreeDocumentUnderStarNode;
+ logger.debug("Finished creating aggregated documents : {}", numAggregatedStarTreeDocument);
+
+ // Create doc values indices in disk
+ createSortedDocValuesIndices(starTreeDocValuesConsumer, fieldNumberAcrossStarTrees);
+
+ // serialize star-tree
+ serializeStarTree(numStarTreeDocument);
+ }
+
+ void appendDocumentsToStarTree(Iterator starTreeDocumentIterator) throws IOException {
+ while (starTreeDocumentIterator.hasNext()) {
+ appendToStarTree(starTreeDocumentIterator.next());
+ }
+ }
+
+ private void serializeStarTree(int numSegmentStarTreeDocument) throws IOException {
+ // serialize the star tree data
+ long dataFilePointer = dataOut.getFilePointer();
+ long totalStarTreeDataLength = StarTreeWriter.writeStarTree(dataOut, rootNode, numStarTreeNodes, starTreeField.getName());
+
+ // serialize the star tree meta
+ StarTreeWriter.writeStarTreeMetadata(
+ metaOut,
+ starTreeField,
+ metricAggregatorInfos,
+ numSegmentStarTreeDocument,
+ dataFilePointer,
+ totalStarTreeDataLength
+ );
+ }
+
+ private void createSortedDocValuesIndices(DocValuesConsumer docValuesConsumer, AtomicInteger fieldNumberAcrossStarTrees)
+ throws IOException {
+ List dimensionWriters = new ArrayList<>();
+ List metricWriters = new ArrayList<>();
+ FieldInfo[] dimensionFieldInfoList = new FieldInfo[starTreeField.getDimensionsOrder().size()];
+ FieldInfo[] metricFieldInfoList = new FieldInfo[metricAggregatorInfos.size()];
+ for (int i = 0; i < dimensionFieldInfoList.length; i++) {
+ final FieldInfo fi = StarTreeUtils.getFieldInfo(
+ fullyQualifiedFieldNameForStarTreeDimensionsDocValues(
+ starTreeField.getName(),
+ starTreeField.getDimensionsOrder().get(i).getField()
+ ),
+ fieldNumberAcrossStarTrees.getAndIncrement()
+ );
+ dimensionFieldInfoList[i] = fi;
+ dimensionWriters.add(new SortedNumericDocValuesWriterWrapper(fi, Counter.newCounter()));
+ }
+ for (int i = 0; i < metricAggregatorInfos.size(); i++) {
+
+ final FieldInfo fi = StarTreeUtils.getFieldInfo(
+ fullyQualifiedFieldNameForStarTreeMetricsDocValues(
+ starTreeField.getName(),
+ metricAggregatorInfos.get(i).getField(),
+ metricAggregatorInfos.get(i).getMetricStat().getTypeName()
+ ),
+ fieldNumberAcrossStarTrees.getAndIncrement()
+ );
+
+ metricFieldInfoList[i] = fi;
+ metricWriters.add(new SortedNumericDocValuesWriterWrapper(fi, Counter.newCounter()));
+ }
+
+ for (int docId = 0; docId < numStarTreeDocs; docId++) {
+ StarTreeDocument starTreeDocument = getStarTreeDocumentForCreatingDocValues(docId);
+ for (int i = 0; i < starTreeDocument.dimensions.length; i++) {
+ Long val = starTreeDocument.dimensions[i];
+ if (val != null) {
+ dimensionWriters.get(i).addValue(docId, val);
+ }
+ }
+
+ for (int i = 0; i < starTreeDocument.metrics.length; i++) {
+ try {
+ switch (metricAggregatorInfos.get(i).getValueAggregators().getAggregatedValueType()) {
+ case LONG:
+ if (starTreeDocument.metrics[i] != null) {
+ metricWriters.get(i).addValue(docId, (Long) starTreeDocument.metrics[i]);
+ }
+ break;
+ case DOUBLE:
+ if (starTreeDocument.metrics[i] != null) {
+ metricWriters.get(i)
+ .addValue(docId, NumericUtils.doubleToSortableLong((Double) starTreeDocument.metrics[i]));
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unknown metric doc value type");
+ }
+ } catch (IllegalArgumentException e) {
+ logger.info("could not parse the value, exiting creation of star tree");
+ }
+ }
+ }
+
+ addStarTreeDocValueFields(docValuesConsumer, dimensionWriters, dimensionFieldInfoList, starTreeField.getDimensionsOrder().size());
+ addStarTreeDocValueFields(docValuesConsumer, metricWriters, metricFieldInfoList, metricAggregatorInfos.size());
+ }
+
+ private void addStarTreeDocValueFields(
+ DocValuesConsumer docValuesConsumer,
+ List docValuesWriters,
+ FieldInfo[] fieldInfoList,
+ int fieldCount
+ ) throws IOException {
+ for (int i = 0; i < fieldCount; i++) {
+ final int increment = i;
+ DocValuesProducer docValuesProducer = new EmptyDocValuesProducer() {
+ @Override
+ public SortedNumericDocValues getSortedNumeric(FieldInfo field) {
+ return docValuesWriters.get(increment).getDocValues();
+ }
+ };
+ docValuesConsumer.addSortedNumericField(fieldInfoList[i], docValuesProducer);
+ }
+ }
+
/**
* Get star tree document from the segment for the current docId with the dimensionReaders and metricReaders
*/
@@ -187,6 +423,15 @@ protected StarTreeDocument getStarTreeDocument(
*/
public abstract StarTreeDocument getStarTreeDocument(int docId) throws IOException;
+ /**
+ * Returns the star-tree document for the given doc id while creating doc values
+ *
+ * @param docId document id
+ * @return star tree document
+ * @throws IOException if an I/O error occurs while fetching the star-tree document
+ */
+ public abstract StarTreeDocument getStarTreeDocumentForCreatingDocValues(int docId) throws IOException;
+
/**
* Retrieves the list of star-tree documents in the star-tree.
*
@@ -360,6 +605,7 @@ protected StarTreeDocument reduceSegmentStarTreeDocuments(
*/
private static Long getLong(Object metric) {
Long metricValue = null;
+
if (metric instanceof Long) {
metricValue = (long) metric;
}
@@ -406,123 +652,6 @@ public StarTreeDocument reduceStarTreeDocuments(StarTreeDocument aggregatedDocum
}
}
- /**
- * Builds the star tree from the original segment documents
- *
- * @param fieldProducerMap contain s the docValues producer to get docValues associated with each field
- * @throws IOException when we are unable to build star-tree
- */
- public void build(Map fieldProducerMap) throws IOException {
- long startTime = System.currentTimeMillis();
- logger.debug("Star-tree build is a go with star tree field {}", starTreeField.getName());
- if (totalSegmentDocs == 0) {
- logger.debug("No documents found in the segment");
- return;
- }
- List metricReaders = getMetricReaders(state, fieldProducerMap);
- List dimensionsSplitOrder = starTreeField.getDimensionsOrder();
- SequentialDocValuesIterator[] dimensionReaders = new SequentialDocValuesIterator[dimensionsSplitOrder.size()];
- for (int i = 0; i < numDimensions; i++) {
- String dimension = dimensionsSplitOrder.get(i).getField();
- FieldInfo dimensionFieldInfo = state.fieldInfos.fieldInfo(dimension);
- if (dimensionFieldInfo == null) {
- dimensionFieldInfo = getFieldInfo(dimension);
- }
- dimensionReaders[i] = new SequentialDocValuesIterator(
- fieldProducerMap.get(dimensionFieldInfo.name).getSortedNumeric(dimensionFieldInfo)
- );
- }
- Iterator starTreeDocumentIterator = sortAndAggregateSegmentDocuments(dimensionReaders, metricReaders);
- logger.debug("Sorting and aggregating star-tree in ms : {}", (System.currentTimeMillis() - startTime));
- build(starTreeDocumentIterator);
- logger.debug("Finished Building star-tree in ms : {}", (System.currentTimeMillis() - startTime));
- }
-
- private static FieldInfo getFieldInfo(String field) {
- return new FieldInfo(
- field,
- 1,
- false,
- false,
- false,
- IndexOptions.NONE,
- DocValuesType.SORTED_NUMERIC,
- -1,
- Collections.emptyMap(),
- 0,
- 0,
- 0,
- 0,
- VectorEncoding.FLOAT32,
- VectorSimilarityFunction.EUCLIDEAN,
- false,
- false
- );
- }
-
- /**
- * Generates the configuration required to perform aggregation for all the metrics on a field
- *
- * @return list of MetricAggregatorInfo
- */
- public List getMetricReaders(SegmentWriteState state, Map fieldProducerMap)
- throws IOException {
- List metricReaders = new ArrayList<>();
- for (Metric metric : this.starTreeField.getMetrics()) {
- for (MetricStat metricStat : metric.getMetrics()) {
- FieldInfo metricFieldInfo = state.fieldInfos.fieldInfo(metric.getField());
- if (metricFieldInfo == null) {
- metricFieldInfo = getFieldInfo(metric.getField());
- }
-
- SequentialDocValuesIterator metricReader = new SequentialDocValuesIterator(
- fieldProducerMap.get(metricFieldInfo.name).getSortedNumeric(metricFieldInfo)
- );
- metricReaders.add(metricReader);
- }
- }
- return metricReaders;
- }
-
- /**
- * Builds the star tree using Star-Tree Document
- *
- * @param starTreeDocumentIterator contains the sorted and aggregated documents
- * @throws IOException when we are unable to build star-tree
- */
- void build(Iterator starTreeDocumentIterator) throws IOException {
- int numSegmentStarTreeDocument = totalSegmentDocs;
-
- while (starTreeDocumentIterator.hasNext()) {
- appendToStarTree(starTreeDocumentIterator.next());
- }
- int numStarTreeDocument = numStarTreeDocs;
- logger.debug("Generated star tree docs : [{}] from segment docs : [{}]", numStarTreeDocument, numSegmentStarTreeDocument);
-
- if (numStarTreeDocs == 0) {
- // TODO: Uncomment when segment codec and file formats is ready
- // StarTreeBuilderUtils.serializeTree(indexOutput, rootNode, dimensionsSplitOrder, numNodes);
- return;
- }
-
- constructStarTree(rootNode, 0, numStarTreeDocs);
- int numStarTreeDocumentUnderStarNode = numStarTreeDocs - numStarTreeDocument;
- logger.debug(
- "Finished constructing star-tree, got [ {} ] tree nodes and [ {} ] starTreeDocument under star-node",
- numStarTreeNodes,
- numStarTreeDocumentUnderStarNode
- );
-
- createAggregatedDocs(rootNode);
- int numAggregatedStarTreeDocument = numStarTreeDocs - numStarTreeDocument - numStarTreeDocumentUnderStarNode;
- logger.debug("Finished creating aggregated documents : {}", numAggregatedStarTreeDocument);
-
- // TODO: When StarTree Codec is ready
- // Create doc values indices in disk
- // Serialize and save in disk
- // Write star tree metadata for off heap implementation
- }
-
/**
* Adds a document to star-tree
*
@@ -539,9 +668,9 @@ private void appendToStarTree(StarTreeDocument starTreeDocument) throws IOExcept
*
* @return return new star-tree node
*/
- private TreeNode getNewNode() {
+ private InMemoryTreeNode getNewNode() {
numStarTreeNodes++;
- return new TreeNode();
+ return new InMemoryTreeNode();
}
/**
@@ -552,7 +681,7 @@ private TreeNode getNewNode() {
* @param endDocId end document id
* @throws IOException throws an exception if we are unable to construct the tree
*/
- private void constructStarTree(TreeNode node, int startDocId, int endDocId) throws IOException {
+ private void constructStarTree(InMemoryTreeNode node, int startDocId, int endDocId) throws IOException {
int childDimensionId = node.dimensionId + 1;
if (childDimensionId == numDimensions) {
@@ -561,7 +690,7 @@ private void constructStarTree(TreeNode node, int startDocId, int endDocId) thro
// Construct all non-star children nodes
node.childDimensionId = childDimensionId;
- Map children = constructNonStarNodes(startDocId, endDocId, childDimensionId);
+ Map children = constructNonStarNodes(startDocId, endDocId, childDimensionId);
node.children = children;
// Construct star-node if required
@@ -570,7 +699,7 @@ private void constructStarTree(TreeNode node, int startDocId, int endDocId) thro
}
// Further split on child nodes if required
- for (TreeNode child : children.values()) {
+ for (InMemoryTreeNode child : children.values()) {
if (child.endDocId - child.startDocId > maxLeafDocuments) {
constructStarTree(child, child.startDocId, child.endDocId);
}
@@ -586,16 +715,21 @@ private void constructStarTree(TreeNode node, int startDocId, int endDocId) thro
* @return root node with non-star nodes constructed
* @throws IOException throws an exception if we are unable to construct non-star nodes
*/
- private Map constructNonStarNodes(int startDocId, int endDocId, int dimensionId) throws IOException {
- Map nodes = new HashMap<>();
+ private Map constructNonStarNodes(int startDocId, int endDocId, int dimensionId) throws IOException {
+ Map nodes = new HashMap<>();
int nodeStartDocId = startDocId;
Long nodeDimensionValue = getDimensionValue(startDocId, dimensionId);
for (int i = startDocId + 1; i < endDocId; i++) {
Long dimensionValue = getDimensionValue(i, dimensionId);
if (Objects.equals(dimensionValue, nodeDimensionValue) == false) {
- TreeNode child = getNewNode();
+ InMemoryTreeNode child = getNewNode();
child.dimensionId = dimensionId;
- child.dimensionValue = nodeDimensionValue != null ? nodeDimensionValue : ALL;
+ if (nodeDimensionValue == null) {
+ child.dimensionValue = ALL;
+ child.nodeType = StarTreeNodeType.NULL.getValue();
+ } else {
+ child.dimensionValue = nodeDimensionValue;
+ }
child.startDocId = nodeStartDocId;
child.endDocId = i;
nodes.put(nodeDimensionValue, child);
@@ -604,7 +738,7 @@ private Map constructNonStarNodes(int startDocId, int endDocId,
nodeDimensionValue = dimensionValue;
}
}
- TreeNode lastNode = getNewNode();
+ InMemoryTreeNode lastNode = getNewNode();
lastNode.dimensionId = dimensionId;
lastNode.dimensionValue = nodeDimensionValue != null ? nodeDimensionValue : ALL;
lastNode.startDocId = nodeStartDocId;
@@ -622,16 +756,14 @@ private Map constructNonStarNodes(int startDocId, int endDocId,
* @return root node with star nodes constructed
* @throws IOException throws an exception if we are unable to construct non-star nodes
*/
- private TreeNode constructStarNode(int startDocId, int endDocId, int dimensionId) throws IOException {
- TreeNode starNode = getNewNode();
+ private InMemoryTreeNode constructStarNode(int startDocId, int endDocId, int dimensionId) throws IOException {
+ InMemoryTreeNode starNode = getNewNode();
starNode.dimensionId = dimensionId;
starNode.dimensionValue = ALL;
- starNode.isStarNode = true;
+ starNode.nodeType = StarTreeNodeType.STAR.getValue();
starNode.startDocId = numStarTreeDocs;
Iterator starTreeDocumentIterator = generateStarTreeDocumentsForStarNode(startDocId, endDocId, dimensionId);
- while (starTreeDocumentIterator.hasNext()) {
- appendToStarTree(starTreeDocumentIterator.next());
- }
+ appendDocumentsToStarTree(starTreeDocumentIterator);
starNode.endDocId = numStarTreeDocs;
return starNode;
}
@@ -643,7 +775,7 @@ private TreeNode constructStarNode(int startDocId, int endDocId, int dimensionId
* @return aggregated star-tree documents
* @throws IOException throws an exception upon failing to create new aggregated docs based on star tree
*/
- private StarTreeDocument createAggregatedDocs(TreeNode node) throws IOException {
+ private StarTreeDocument createAggregatedDocs(InMemoryTreeNode node) throws IOException {
StarTreeDocument aggregatedStarTreeDocument = null;
if (node.children == null) {
@@ -670,8 +802,8 @@ private StarTreeDocument createAggregatedDocs(TreeNode node) throws IOException
// For non-leaf node
if (node.children.containsKey((long) ALL)) {
// If it has star child, use the star child aggregated document directly
- for (TreeNode child : node.children.values()) {
- if (child.isStarNode) {
+ for (InMemoryTreeNode child : node.children.values()) {
+ if (child.nodeType == StarTreeNodeType.STAR.getValue()) {
aggregatedStarTreeDocument = createAggregatedDocs(child);
node.aggregatedDocId = child.aggregatedDocId;
} else {
@@ -681,12 +813,12 @@ private StarTreeDocument createAggregatedDocs(TreeNode node) throws IOException
} else {
// If no star child exists, aggregate all aggregated documents from non-star children
if (node.children.values().size() == 1) {
- for (TreeNode child : node.children.values()) {
+ for (InMemoryTreeNode child : node.children.values()) {
aggregatedStarTreeDocument = reduceStarTreeDocuments(aggregatedStarTreeDocument, createAggregatedDocs(child));
node.aggregatedDocId = child.aggregatedDocId;
}
} else {
- for (TreeNode child : node.children.values()) {
+ for (InMemoryTreeNode child : node.children.values()) {
aggregatedStarTreeDocument = reduceStarTreeDocuments(aggregatedStarTreeDocument, createAggregatedDocs(child));
}
if (null == aggregatedStarTreeDocument) {
@@ -721,7 +853,7 @@ public void close() throws IOException {
abstract Iterator mergeStarTrees(List starTreeValues) throws IOException;
- public TreeNode getRootNode() {
+ public InMemoryTreeNode getRootNode() {
return rootNode;
}
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OffHeapStarTreeBuilder.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OffHeapStarTreeBuilder.java
index f63b0cb0cc77d..ee1b9c90a2768 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OffHeapStarTreeBuilder.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OffHeapStarTreeBuilder.java
@@ -10,14 +10,16 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.store.IndexOutput;
import org.opensearch.common.annotation.ExperimentalApi;
import org.opensearch.common.util.io.IOUtils;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
import org.opensearch.index.compositeindex.datacube.Dimension;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeDocument;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import org.opensearch.index.compositeindex.datacube.startree.utils.SequentialDocValuesIterator;
import org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeDocumentsSorter;
import org.opensearch.index.mapper.MapperService;
@@ -31,9 +33,13 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.SEGMENT_DOCS_COUNT;
/**
* Off-heap implementation of the star tree builder.
+ *
* @opensearch.experimental
*/
@ExperimentalApi
@@ -46,12 +52,20 @@ public class OffHeapStarTreeBuilder extends BaseStarTreeBuilder {
* Builds star tree based on star tree field configuration consisting of dimensions, metrics and star tree index
* specific configuration.
*
+ * @param metaOut an index output to write star-tree metadata
+ * @param dataOut an index output to write star-tree data
* @param starTreeField holds the configuration for the star tree
* @param state stores the segment write state
* @param mapperService helps to find the original type of the field
*/
- protected OffHeapStarTreeBuilder(StarTreeField starTreeField, SegmentWriteState state, MapperService mapperService) throws IOException {
- super(starTreeField, state, mapperService);
+ protected OffHeapStarTreeBuilder(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ StarTreeField starTreeField,
+ SegmentWriteState state,
+ MapperService mapperService
+ ) throws IOException {
+ super(metaOut, dataOut, starTreeField, state, mapperService);
segmentDocumentFileManager = new SegmentDocsFileManager(state, starTreeField, metricAggregatorInfos);
try {
starTreeDocumentFileManager = new StarTreeDocsFileManager(state, starTreeField, metricAggregatorInfos);
@@ -73,10 +87,14 @@ public void appendStarTreeDocument(StarTreeDocument starTreeDocument) throws IOE
* @param starTreeValuesSubs contains the star tree values from multiple segments
*/
@Override
- public void build(List starTreeValuesSubs) throws IOException {
+ public void build(
+ List starTreeValuesSubs,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
boolean success = false;
try {
- build(mergeStarTrees(starTreeValuesSubs));
+ build(mergeStarTrees(starTreeValuesSubs), fieldNumberAcrossStarTrees, starTreeDocValuesConsumer);
success = true;
} finally {
starTreeDocumentFileManager.deleteFiles(success);
@@ -141,7 +159,7 @@ Iterator mergeStarTrees(List starTreeValuesSub
}
int currentDocId = 0;
int numSegmentDocs = Integer.parseInt(
- starTreeValues.getAttributes().getOrDefault(NUM_SEGMENT_DOCS, String.valueOf(DocIdSetIterator.NO_MORE_DOCS))
+ starTreeValues.getAttributes().getOrDefault(SEGMENT_DOCS_COUNT, String.valueOf(DocIdSetIterator.NO_MORE_DOCS))
);
while (currentDocId < numSegmentDocs) {
StarTreeDocument starTreeDocument = getStarTreeDocument(currentDocId, dimensionReaders, metricReaders);
@@ -242,6 +260,11 @@ public StarTreeDocument getStarTreeDocument(int docId) throws IOException {
return starTreeDocumentFileManager.readStarTreeDocument(docId, true);
}
+ @Override
+ public StarTreeDocument getStarTreeDocumentForCreatingDocValues(int docId) throws IOException {
+ return getStarTreeDocument(docId);
+ }
+
// This should be only used for testing
@Override
public List getStarTreeDocuments() throws IOException {
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OnHeapStarTreeBuilder.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OnHeapStarTreeBuilder.java
index 8ff111d3b41d9..c18c55e0bb1a5 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OnHeapStarTreeBuilder.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/OnHeapStarTreeBuilder.java
@@ -7,13 +7,15 @@
*/
package org.opensearch.index.compositeindex.datacube.startree.builder;
+import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.store.IndexOutput;
import org.opensearch.common.annotation.ExperimentalApi;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
import org.opensearch.index.compositeindex.datacube.Dimension;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeDocument;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import org.opensearch.index.compositeindex.datacube.startree.utils.SequentialDocValuesIterator;
import org.opensearch.index.mapper.MapperService;
@@ -24,6 +26,9 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.SEGMENT_DOCS_COUNT;
/**
* On heap single tree builder
@@ -38,12 +43,20 @@ public class OnHeapStarTreeBuilder extends BaseStarTreeBuilder {
/**
* Constructor for OnHeapStarTreeBuilder
*
+ * @param metaOut an index output to write star-tree metadata
+ * @param dataOut an index output to write star-tree data
* @param starTreeField star-tree field
* @param segmentWriteState segment write state
* @param mapperService helps with the numeric type of field
*/
- public OnHeapStarTreeBuilder(StarTreeField starTreeField, SegmentWriteState segmentWriteState, MapperService mapperService) {
- super(starTreeField, segmentWriteState, mapperService);
+ public OnHeapStarTreeBuilder(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ StarTreeField starTreeField,
+ SegmentWriteState segmentWriteState,
+ MapperService mapperService
+ ) throws IOException {
+ super(metaOut, dataOut, starTreeField, segmentWriteState, mapperService);
}
@Override
@@ -84,12 +97,16 @@ public Iterator sortAndAggregateSegmentDocuments(
// TODO : we can save empty iterator for dimensions which are not part of segment
starTreeDocuments[currentDocId] = getSegmentStarTreeDocument(currentDocId, dimensionReaders, metricReaders);
}
- return sortAndAggregateStarTreeDocuments(starTreeDocuments);
+ return sortAndAggregateStarTreeDocuments(starTreeDocuments, false);
}
@Override
- public void build(List starTreeValuesSubs) throws IOException {
- build(mergeStarTrees(starTreeValuesSubs));
+ public void build(
+ List starTreeValuesSubs,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
+ build(mergeStarTrees(starTreeValuesSubs), fieldNumberAcrossStarTrees, starTreeDocValuesConsumer);
}
/**
@@ -108,7 +125,7 @@ Iterator mergeStarTrees(List starTreeValuesSub
* Returns an array of all the starTreeDocuments from all the segments
* We only take the non-star documents from all the segments.
*
- * @param starTreeValuesSubs StarTreeValues from multiple segments
+ * @param starTreeValuesSubs StarTreeValues from multiple segmentsx
* @return array of star tree documents
*/
StarTreeDocument[] getSegmentsStarTreeDocuments(List starTreeValuesSubs) throws IOException {
@@ -129,7 +146,7 @@ StarTreeDocument[] getSegmentsStarTreeDocuments(List starTreeVal
int currentDocId = 0;
int numSegmentDocs = Integer.parseInt(
- starTreeValues.getAttributes().getOrDefault(NUM_SEGMENT_DOCS, String.valueOf(DocIdSetIterator.NO_MORE_DOCS))
+ starTreeValues.getAttributes().getOrDefault(SEGMENT_DOCS_COUNT, String.valueOf(DocIdSetIterator.NO_MORE_DOCS))
);
while (currentDocId < numSegmentDocs) {
starTreeDocuments.add(getStarTreeDocument(currentDocId, dimensionReaders, metricReaders));
@@ -140,8 +157,9 @@ StarTreeDocument[] getSegmentsStarTreeDocuments(List starTreeVal
return starTreeDocuments.toArray(starTreeDocumentsArr);
}
- Iterator sortAndAggregateStarTreeDocuments(StarTreeDocument[] starTreeDocuments) {
- return sortAndAggregateStarTreeDocuments(starTreeDocuments, false);
+ @Override
+ public StarTreeDocument getStarTreeDocumentForCreatingDocValues(int docId) throws IOException {
+ return starTreeDocuments.get(docId);
}
/**
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreeBuilder.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreeBuilder.java
index 94c9c9f2efb18..547e86216753a 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreeBuilder.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreeBuilder.java
@@ -8,14 +8,16 @@
package org.opensearch.index.compositeindex.datacube.startree.builder;
+import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.codecs.DocValuesProducer;
import org.opensearch.common.annotation.ExperimentalApi;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A star-tree builder that builds a single star-tree.
@@ -27,17 +29,29 @@ public interface StarTreeBuilder extends Closeable {
/**
* Builds the star tree from the original segment documents
*
- * @param fieldProducerMap contains the docValues producer to get docValues associated with each field
+ * @param fieldProducerMap contains the docValues producer to get docValues associated with each field
+ * @param fieldNumberAcrossStarTrees maintains the unique field number across the fields in the star tree
+ * @param starTreeDocValuesConsumer consumer of star-tree doc values
* @throws IOException when we are unable to build star-tree
*/
- void build(Map fieldProducerMap) throws IOException;
+ void build(
+ Map fieldProducerMap,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException;
/**
- * Builds the star tree using StarTree values from multiple segments
+ * Builds the star tree using Tree values from multiple segments
*
* @param starTreeValuesSubs contains the star tree values from multiple segments
+ * @param fieldNumberAcrossStarTrees maintains the unique field number across the fields in the star tree
+ * @param starTreeDocValuesConsumer consumer of star-tree doc values
* @throws IOException when we are unable to build star-tree
*/
- void build(List starTreeValuesSubs) throws IOException;
+ void build(
+ List starTreeValuesSubs,
+ AtomicInteger fieldNumberAcrossStarTrees,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException;
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreesBuilder.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreesBuilder.java
index 3b376d7c34351..486b82506e301 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreesBuilder.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/builder/StarTreesBuilder.java
@@ -10,11 +10,13 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.apache.lucene.codecs.DocValuesConsumer;
import org.apache.lucene.codecs.DocValuesProducer;
import org.apache.lucene.index.SegmentWriteState;
+import org.apache.lucene.store.IndexOutput;
import org.opensearch.common.annotation.ExperimentalApi;
-import org.opensearch.index.codec.composite.datacube.startree.StarTreeValues;
import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import org.opensearch.index.mapper.CompositeMappedFieldType;
import org.opensearch.index.mapper.MapperService;
import org.opensearch.index.mapper.StarTreeMapper;
@@ -25,6 +27,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Builder to construct star-trees based on multiple star-tree fields.
@@ -39,6 +42,7 @@ public class StarTreesBuilder implements Closeable {
private final List starTreeFields;
private final SegmentWriteState state;
private final MapperService mapperService;
+ private AtomicInteger fieldNumberAcrossStarTrees;
public StarTreesBuilder(SegmentWriteState segmentWriteState, MapperService mapperService) {
List starTreeFields = new ArrayList<>();
@@ -58,12 +62,24 @@ public StarTreesBuilder(SegmentWriteState segmentWriteState, MapperService mappe
this.starTreeFields = starTreeFields;
this.state = segmentWriteState;
this.mapperService = mapperService;
+ this.fieldNumberAcrossStarTrees = new AtomicInteger();
}
/**
- * Builds the star-trees.
+ * Builds all star-trees for given star-tree fields.
+ *
+ * @param metaOut an IndexInput for star-tree metadata
+ * @param dataOut an IndexInput for star-tree data
+ * @param fieldProducerMap fetches iterators for the fields (dimensions and metrics)
+ * @param starTreeDocValuesConsumer a consumer to write star-tree doc values
+ * @throws IOException when an error occurs while building the star-trees
*/
- public void build(Map fieldProducerMap) throws IOException {
+ public void build(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ Map fieldProducerMap,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
if (starTreeFields.isEmpty()) {
logger.debug("no star-tree fields found, returning from star-tree builder");
return;
@@ -75,8 +91,8 @@ public void build(Map fieldProducerMap) throws IOExce
// Build all star-trees
for (StarTreeField starTreeField : starTreeFields) {
- try (StarTreeBuilder starTreeBuilder = getStarTreeBuilder(starTreeField, state, mapperService)) {
- starTreeBuilder.build(fieldProducerMap);
+ try (StarTreeBuilder starTreeBuilder = getStarTreeBuilder(metaOut, dataOut, starTreeField, state, mapperService)) {
+ starTreeBuilder.build(fieldProducerMap, fieldNumberAcrossStarTrees, starTreeDocValuesConsumer);
}
}
logger.debug("Took {} ms to build {} star-trees with star-tree fields", System.currentTimeMillis() - startTime, numStarTrees);
@@ -90,9 +106,17 @@ public void close() throws IOException {
/**
* Merges star tree fields from multiple segments
*
+ * @param metaOut an IndexInput for star-tree metadata
+ * @param dataOut an IndexInput for star-tree data
* @param starTreeValuesSubsPerField starTreeValuesSubs per field
+ * @param starTreeDocValuesConsumer a consumer to write star-tree doc values
*/
- public void buildDuringMerge(final Map> starTreeValuesSubsPerField) throws IOException {
+ public void buildDuringMerge(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ final Map> starTreeValuesSubsPerField,
+ DocValuesConsumer starTreeDocValuesConsumer
+ ) throws IOException {
logger.debug("Starting merge of {} star-trees with star-tree fields", starTreeValuesSubsPerField.size());
long startTime = System.currentTimeMillis();
for (Map.Entry> entry : starTreeValuesSubsPerField.entrySet()) {
@@ -102,8 +126,9 @@ public void buildDuringMerge(final Map> starTreeVal
continue;
}
StarTreeField starTreeField = starTreeValuesList.get(0).getStarTreeField();
- try (StarTreeBuilder builder = getStarTreeBuilder(starTreeField, state, mapperService)) {
- builder.build(starTreeValuesList);
+ try (StarTreeBuilder builder = getStarTreeBuilder(metaOut, dataOut, starTreeField, state, mapperService)) {
+ builder.build(starTreeValuesList, fieldNumberAcrossStarTrees, starTreeDocValuesConsumer);
+ builder.close();
}
}
logger.debug(
@@ -116,13 +141,18 @@ public void buildDuringMerge(final Map> starTreeVal
/**
* Get star-tree builder based on build mode.
*/
- StarTreeBuilder getStarTreeBuilder(StarTreeField starTreeField, SegmentWriteState state, MapperService mapperService)
- throws IOException {
+ StarTreeBuilder getStarTreeBuilder(
+ IndexOutput metaOut,
+ IndexOutput dataOut,
+ StarTreeField starTreeField,
+ SegmentWriteState state,
+ MapperService mapperService
+ ) throws IOException {
switch (starTreeField.getStarTreeConfig().getBuildMode()) {
case ON_HEAP:
- return new OnHeapStarTreeBuilder(starTreeField, state, mapperService);
+ return new OnHeapStarTreeBuilder(metaOut, dataOut, starTreeField, state, mapperService);
case OFF_HEAP:
- return new OffHeapStarTreeBuilder(starTreeField, state, mapperService);
+ return new OffHeapStarTreeBuilder(metaOut, dataOut, starTreeField, state, mapperService);
default:
throw new IllegalArgumentException(
String.format(
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/StarTreeWriter.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/StarTreeWriter.java
new file mode 100644
index 0000000000000..00355fd187f49
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/StarTreeWriter.java
@@ -0,0 +1,78 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+package org.opensearch.index.compositeindex.datacube.startree.fileformats;
+
+import org.apache.lucene.store.IndexOutput;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.aggregators.MetricAggregatorInfo;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.data.StarTreeDataWriter;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.StarTreeMetaWriter;
+import org.opensearch.index.compositeindex.datacube.startree.node.InMemoryTreeNode;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Util class for building star tree
+ *
+ * @opensearch.experimental
+ */
+public class StarTreeWriter {
+
+ /** Initial version for the star tree writer */
+ public static final int VERSION_START = 0;
+
+ /** Current version for the star tree writer */
+ public static final int VERSION_CURRENT = VERSION_START;
+
+ private StarTreeWriter() {}
+
+ /**
+ * Write star tree to index output stream
+ *
+ * @param dataOut data index output
+ * @param rootNode root star-tree node
+ * @param numNodes number of nodes in the tree
+ * @param name name of the star-tree field
+ * @return total size of the three
+ * @throws IOException when star-tree data serialization fails
+ */
+ public static long writeStarTree(IndexOutput dataOut, InMemoryTreeNode rootNode, int numNodes, String name) throws IOException {
+ return StarTreeDataWriter.writeStarTree(dataOut, rootNode, numNodes, name);
+ }
+
+ /**
+ * Write star tree metadata to index output stream
+ *
+ * @param metaOut meta index output
+ * @param starTreeField star tree field
+ * @param metricAggregatorInfos metric aggregator infos
+ * @param segmentAggregatedCount segment aggregated count
+ * @param dataFilePointer data file pointer
+ * @param dataFileLength data file length
+ * @throws IOException when star-tree data serialization fails
+ */
+ public static void writeStarTreeMetadata(
+ IndexOutput metaOut,
+ StarTreeField starTreeField,
+ List metricAggregatorInfos,
+ Integer segmentAggregatedCount,
+ long dataFilePointer,
+ long dataFileLength
+ ) throws IOException {
+ StarTreeMetaWriter.writeStarTreeMetadata(
+ metaOut,
+ starTreeField,
+ metricAggregatorInfos,
+ segmentAggregatedCount,
+ dataFilePointer,
+ dataFileLength
+ );
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/StarTreeDataWriter.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/StarTreeDataWriter.java
new file mode 100644
index 0000000000000..5ac47e5927d4f
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/StarTreeDataWriter.java
@@ -0,0 +1,142 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.data;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.store.IndexOutput;
+import org.opensearch.index.compositeindex.datacube.startree.node.InMemoryTreeNode;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.COMPOSITE_FIELD_MARKER;
+import static org.opensearch.index.compositeindex.datacube.startree.fileformats.StarTreeWriter.VERSION_CURRENT;
+import static org.opensearch.index.compositeindex.datacube.startree.node.FixedLengthStarTreeNode.SERIALIZABLE_DATA_SIZE_IN_BYTES;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.ALL;
+
+/**
+ * Utility class for serializing a star-tree data structure.
+ *
+ * @opensearch.experimental
+ */
+public class StarTreeDataWriter {
+
+ private static final Logger logger = LogManager.getLogger(StarTreeDataWriter.class);
+
+ /**
+ * Writes the star-tree data structure.
+ *
+ * @param indexOutput the IndexOutput to write the star-tree data
+ * @param rootNode the root node of the star-tree
+ * @param numNodes the total number of nodes in the star-tree
+ * @param name the name of the star-tree field
+ * @return the total size in bytes of the serialized star-tree data
+ * @throws IOException if an I/O error occurs while writing the star-tree data
+ */
+ public static long writeStarTree(IndexOutput indexOutput, InMemoryTreeNode rootNode, int numNodes, String name) throws IOException {
+ long totalSizeInBytes = 0L;
+ totalSizeInBytes += computeStarTreeDataHeaderByteSize();
+ totalSizeInBytes += (long) numNodes * SERIALIZABLE_DATA_SIZE_IN_BYTES;
+
+ logger.debug("Star tree data size in bytes : {} for star-tree field {}", totalSizeInBytes, name);
+
+ writeStarTreeHeader(indexOutput, numNodes);
+ writeStarTreeNodes(indexOutput, rootNode);
+ return totalSizeInBytes;
+ }
+
+ /**
+ * Computes the byte size of the star-tree data header.
+ *
+ * @return the byte size of the star-tree data header
+ */
+ public static int computeStarTreeDataHeaderByteSize() {
+ // Magic marker (8), version (4)
+ int headerSizeInBytes = 12;
+
+ // For number of nodes.
+ headerSizeInBytes += Integer.BYTES;
+ return headerSizeInBytes;
+ }
+
+ /**
+ * Writes the star-tree data header.
+ *
+ * @param output the IndexOutput to write the header
+ * @param numNodes the total number of nodes in the star-tree
+ * @throws IOException if an I/O error occurs while writing the header
+ */
+ private static void writeStarTreeHeader(IndexOutput output, int numNodes) throws IOException {
+ output.writeLong(COMPOSITE_FIELD_MARKER);
+ output.writeInt(VERSION_CURRENT);
+ output.writeInt(numNodes);
+ }
+
+ /**
+ * Writes the star-tree nodes in a breadth-first order.
+ *
+ * @param output the IndexOutput to write the nodes
+ * @param rootNode the root node of the star-tree
+ * @throws IOException if an I/O error occurs while writing the nodes
+ */
+ private static void writeStarTreeNodes(IndexOutput output, InMemoryTreeNode rootNode) throws IOException {
+ Queue queue = new LinkedList<>();
+ queue.add(rootNode);
+
+ int currentNodeId = 0;
+ while (!queue.isEmpty()) {
+ InMemoryTreeNode node = queue.remove();
+
+ if (node.children == null || node.children.isEmpty()) {
+ writeStarTreeNode(output, node, ALL, ALL);
+ } else {
+
+ // Sort all children nodes based on dimension value
+ List sortedChildren = new ArrayList<>(node.children.values());
+ sortedChildren.sort(
+ Comparator.comparingInt(InMemoryTreeNode::getNodeType).thenComparingLong(InMemoryTreeNode::getDimensionValue)
+ );
+
+ int firstChildId = currentNodeId + queue.size() + 1;
+ int lastChildId = firstChildId + sortedChildren.size() - 1;
+ writeStarTreeNode(output, node, firstChildId, lastChildId);
+
+ queue.addAll(sortedChildren);
+ }
+
+ currentNodeId++;
+ }
+ }
+
+ /**
+ * Writes a single star-tree node
+ *
+ * @param output the IndexOutput to write the node
+ * @param node the star tree node to write
+ * @param firstChildId the ID of the first child node
+ * @param lastChildId the ID of the last child node
+ * @throws IOException if an I/O error occurs while writing the node
+ */
+ private static void writeStarTreeNode(IndexOutput output, InMemoryTreeNode node, int firstChildId, int lastChildId) throws IOException {
+ output.writeInt(node.dimensionId);
+ output.writeLong(node.dimensionValue);
+ output.writeInt(node.startDocId);
+ output.writeInt(node.endDocId);
+ output.writeInt(node.aggregatedDocId);
+ output.writeByte(node.nodeType);
+ output.writeInt(firstChildId);
+ output.writeInt(lastChildId);
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/package-info.java
similarity index 57%
rename from server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/package-info.java
rename to server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/package-info.java
index 67808ad51289a..1c6df3886e08d 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/datacube/startree/package-info.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/data/package-info.java
@@ -7,6 +7,8 @@
*/
/**
- * classes responsible for handling all star tree structures and operations as part of codec
+ * Writer package for star tree
+ *
+ * @opensearch.experimental
*/
-package org.opensearch.index.codec.composite.datacube.startree;
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.data;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/MetricEntry.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/MetricEntry.java
new file mode 100644
index 0000000000000..357c8a49f600c
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/MetricEntry.java
@@ -0,0 +1,55 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.meta;
+
+import org.opensearch.index.compositeindex.datacube.MetricStat;
+
+import java.util.Objects;
+
+/**
+ * Holds the pair of metric name and it's associated stat
+ *
+ * @opensearch.experimental
+ */
+public class MetricEntry {
+
+ private final String metricFieldName;
+ private final MetricStat metricStat;
+
+ public MetricEntry(String metricFieldName, MetricStat metricStat) {
+ this.metricFieldName = metricFieldName;
+ this.metricStat = metricStat;
+ }
+
+ public String getMetricFieldName() {
+ return metricFieldName;
+ }
+
+ public MetricStat getMetricStat() {
+ return metricStat;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(metricFieldName + metricStat.getTypeName());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof MetricEntry) {
+ MetricEntry anotherPair = (MetricEntry) obj;
+ return metricStat.equals(anotherPair.metricStat) && metricFieldName.equals(anotherPair.metricFieldName);
+ }
+ return false;
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetaWriter.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetaWriter.java
new file mode 100644
index 0000000000000..057d5e908d9d6
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetaWriter.java
@@ -0,0 +1,156 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.meta;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.store.IndexOutput;
+import org.opensearch.index.compositeindex.datacube.Dimension;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.aggregators.MetricAggregatorInfo;
+import org.opensearch.index.mapper.CompositeMappedFieldType;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.COMPOSITE_FIELD_MARKER;
+import static org.opensearch.index.compositeindex.datacube.startree.fileformats.StarTreeWriter.VERSION_CURRENT;
+
+/**
+ * The utility class for serializing the metadata of a star-tree data structure.
+ * The metadata includes information about the dimensions, metrics, and other relevant details
+ * related to the star tree.
+ *
+ * @opensearch.experimental
+ */
+public class StarTreeMetaWriter {
+
+ private static final Logger logger = LogManager.getLogger(StarTreeMetaWriter.class);
+
+ /**
+ * Writes the star-tree metadata.
+ *
+ * @param metaOut the IndexOutput to write the metadata
+ * @param starTreeField the star-tree field
+ * @param metricAggregatorInfos the list of metric aggregator information
+ * @param segmentAggregatedCount the aggregated document count for the segment
+ * @param dataFilePointer the file pointer to the start of the star tree data
+ * @param dataFileLength the length of the star tree data file
+ * @throws IOException if an I/O error occurs while serializing the metadata
+ */
+ public static void writeStarTreeMetadata(
+ IndexOutput metaOut,
+ StarTreeField starTreeField,
+ List metricAggregatorInfos,
+ Integer segmentAggregatedCount,
+ long dataFilePointer,
+ long dataFileLength
+ ) throws IOException {
+
+ long initialMetaFilePointer = metaOut.getFilePointer();
+
+ writeMetaHeader(metaOut, CompositeMappedFieldType.CompositeFieldType.STAR_TREE, starTreeField.getName());
+ writeMeta(metaOut, metricAggregatorInfos, starTreeField, segmentAggregatedCount, dataFilePointer, dataFileLength);
+
+ logger.debug(
+ "Star tree meta size in bytes : {} for star-tree field {}",
+ metaOut.getFilePointer() - initialMetaFilePointer,
+ starTreeField.getName()
+ );
+ }
+
+ /**
+ * Writes the star-tree metadata header.
+ *
+ * @param metaOut the IndexOutput to write the header
+ * @param compositeFieldType the composite field type of the star-tree field
+ * @param starTreeFieldName the name of the star-tree field
+ * @throws IOException if an I/O error occurs while writing the header
+ */
+ private static void writeMetaHeader(
+ IndexOutput metaOut,
+ CompositeMappedFieldType.CompositeFieldType compositeFieldType,
+ String starTreeFieldName
+ ) throws IOException {
+ // magic marker for sanity
+ metaOut.writeLong(COMPOSITE_FIELD_MARKER);
+
+ // version
+ metaOut.writeVInt(VERSION_CURRENT);
+
+ // star tree field name
+ metaOut.writeString(starTreeFieldName);
+
+ // star tree field type
+ metaOut.writeString(compositeFieldType.getName());
+ }
+
+ /**
+ * Writes the star-tree metadata.
+ *
+ * @param metaOut the IndexOutput to write the metadata
+ * @param metricAggregatorInfos the list of metric aggregator information
+ * @param starTreeField the star tree field
+ * @param segmentAggregatedDocCount the aggregated document count for the segment
+ * @param dataFilePointer the file pointer to the start of the star-tree data
+ * @param dataFileLength the length of the star-tree data file
+ * @throws IOException if an I/O error occurs while writing the metadata
+ */
+ private static void writeMeta(
+ IndexOutput metaOut,
+ List metricAggregatorInfos,
+ StarTreeField starTreeField,
+ Integer segmentAggregatedDocCount,
+ long dataFilePointer,
+ long dataFileLength
+ ) throws IOException {
+
+ // number of dimensions
+ metaOut.writeVInt(starTreeField.getDimensionsOrder().size());
+
+ // dimensions
+ for (Dimension dimension : starTreeField.getDimensionsOrder()) {
+ metaOut.writeString(dimension.getField());
+ }
+
+ // number of metrics
+ metaOut.writeVInt(metricAggregatorInfos.size());
+
+ // metric - metric stat pair
+ for (MetricAggregatorInfo metricAggregatorInfo : metricAggregatorInfos) {
+ metaOut.writeString(metricAggregatorInfo.getField());
+ int metricStatOrdinal = metricAggregatorInfo.getMetricStat().getMetricOrdinal();
+ metaOut.writeVInt(metricStatOrdinal);
+ }
+
+ // segment aggregated document count
+ metaOut.writeVInt(segmentAggregatedDocCount);
+
+ // max leaf docs
+ metaOut.writeVInt(starTreeField.getStarTreeConfig().maxLeafDocs());
+
+ // number of skip star node creation dimensions
+ metaOut.writeVInt(starTreeField.getStarTreeConfig().getSkipStarNodeCreationInDims().size());
+
+ // skip star node creations
+ for (String dimension : starTreeField.getStarTreeConfig().getSkipStarNodeCreationInDims()) {
+ metaOut.writeString(dimension);
+ }
+
+ // star tree build-mode
+ metaOut.writeByte(starTreeField.getStarTreeConfig().getBuildMode().getBuildModeOrdinal());
+
+ // star-tree data file pointer
+ metaOut.writeVLong(dataFilePointer);
+
+ // star-tree data file length
+ metaOut.writeVLong(dataFileLength);
+
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetadata.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetadata.java
new file mode 100644
index 0000000000000..b1359d4ce8d57
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/StarTreeMetadata.java
@@ -0,0 +1,271 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.meta;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.store.IndexInput;
+import org.opensearch.index.compositeindex.CompositeIndexMetadata;
+import org.opensearch.index.compositeindex.datacube.MetricStat;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeFieldConfiguration;
+import org.opensearch.index.mapper.CompositeMappedFieldType;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Holds the associated metadata for the building of star-tree.
+ *
+ * @opensearch.experimental
+ */
+public class StarTreeMetadata extends CompositeIndexMetadata {
+ private static final Logger logger = LogManager.getLogger(StarTreeMetadata.class);
+ private final IndexInput meta;
+ private final String starTreeFieldName;
+ private final String starTreeFieldType;
+ private final List dimensionFields;
+ private final List metricEntries;
+ private final Integer segmentAggregatedDocCount;
+ private final Integer maxLeafDocs;
+ private final Set skipStarNodeCreationInDims;
+ private final StarTreeFieldConfiguration.StarTreeBuildMode starTreeBuildMode;
+ private final long dataStartFilePointer;
+ private final long dataLength;
+
+ /**
+ * A star tree metadata constructor to initialize star tree metadata from the segment file (.cim) using index input.
+ *
+ * @param metaIn an index input to read star-tree meta
+ * @param compositeFieldName name of the composite field. Here, name of the star-tree field.
+ * @param compositeFieldType type of the composite field. Here, STAR_TREE field.
+ * @throws IOException if unable to read star-tree metadata from the file
+ */
+ public StarTreeMetadata(IndexInput metaIn, String compositeFieldName, CompositeMappedFieldType.CompositeFieldType compositeFieldType)
+ throws IOException {
+ super(compositeFieldName, compositeFieldType);
+ this.meta = metaIn;
+ try {
+ this.starTreeFieldName = this.getCompositeFieldName();
+ this.starTreeFieldType = this.getCompositeFieldType().getName();
+ this.dimensionFields = readStarTreeDimensions();
+ this.metricEntries = readMetricEntries();
+ this.segmentAggregatedDocCount = readSegmentAggregatedDocCount();
+ this.maxLeafDocs = readMaxLeafDocs();
+ this.skipStarNodeCreationInDims = readSkipStarNodeCreationInDims();
+ this.starTreeBuildMode = readBuildMode();
+ this.dataStartFilePointer = readDataStartFilePointer();
+ this.dataLength = readDataLength();
+ } catch (Exception e) {
+ logger.error("Unable to read star-tree metadata from the file");
+ throw new CorruptIndexException("Unable to read star-tree metadata from the file", metaIn);
+ }
+ }
+
+ /**
+ * A star tree metadata constructor to initialize star tree metadata.
+ * Used for testing.
+ *
+ * @param meta an index input to read star-tree meta
+ * @param compositeFieldName name of the composite field. Here, name of the star-tree field.
+ * @param compositeFieldType type of the composite field. Here, STAR_TREE field.
+ * @param dimensionFields list of dimension fields
+ * @param metricEntries list of metric entries
+ * @param segmentAggregatedDocCount segment aggregated doc count
+ * @param maxLeafDocs max leaf docs
+ * @param skipStarNodeCreationInDims set of dimensions to skip star node creation
+ * @param starTreeBuildMode star tree build mode
+ * @param dataStartFilePointer data start file pointer
+ * @param dataLength data length
+ */
+ public StarTreeMetadata(
+ String compositeFieldName,
+ CompositeMappedFieldType.CompositeFieldType compositeFieldType,
+ IndexInput meta,
+ List dimensionFields,
+ List metricEntries,
+ Integer segmentAggregatedDocCount,
+ Integer maxLeafDocs,
+ Set skipStarNodeCreationInDims,
+ StarTreeFieldConfiguration.StarTreeBuildMode starTreeBuildMode,
+ long dataStartFilePointer,
+ long dataLength
+ ) {
+ super(compositeFieldName, compositeFieldType);
+ this.meta = meta;
+ this.starTreeFieldName = compositeFieldName;
+ this.starTreeFieldType = compositeFieldType.getName();
+ this.dimensionFields = dimensionFields;
+ this.metricEntries = metricEntries;
+ this.segmentAggregatedDocCount = segmentAggregatedDocCount;
+ this.maxLeafDocs = maxLeafDocs;
+ this.skipStarNodeCreationInDims = skipStarNodeCreationInDims;
+ this.starTreeBuildMode = starTreeBuildMode;
+ this.dataStartFilePointer = dataStartFilePointer;
+ this.dataLength = dataLength;
+ }
+
+ private int readDimensionsCount() throws IOException {
+ return meta.readVInt();
+ }
+
+ private List readStarTreeDimensions() throws IOException {
+ int dimensionCount = readDimensionsCount();
+ List dimensionFields = new ArrayList<>();
+
+ for (int i = 0; i < dimensionCount; i++) {
+ dimensionFields.add(meta.readString());
+ }
+
+ return dimensionFields;
+ }
+
+ private int readMetricsCount() throws IOException {
+ return meta.readVInt();
+ }
+
+ private List readMetricEntries() throws IOException {
+ int metricCount = readMetricsCount();
+ List metricEntries = new ArrayList<>();
+
+ for (int i = 0; i < metricCount; i++) {
+ String metricFieldName = meta.readString();
+ int metricStatOrdinal = meta.readVInt();
+ metricEntries.add(new MetricEntry(metricFieldName, MetricStat.fromMetricOrdinal(metricStatOrdinal)));
+ }
+
+ return metricEntries;
+ }
+
+ private int readSegmentAggregatedDocCount() throws IOException {
+ return meta.readVInt();
+ }
+
+ private int readMaxLeafDocs() throws IOException {
+ return meta.readVInt();
+ }
+
+ private int readSkipStarNodeCreationInDimsCount() throws IOException {
+ return meta.readVInt();
+ }
+
+ private Set readSkipStarNodeCreationInDims() throws IOException {
+
+ int skipStarNodeCreationInDimsCount = readSkipStarNodeCreationInDimsCount();
+ Set skipStarNodeCreationInDims = new HashSet<>();
+ for (int i = 0; i < skipStarNodeCreationInDimsCount; i++) {
+ skipStarNodeCreationInDims.add(meta.readString());
+ }
+ return skipStarNodeCreationInDims;
+ }
+
+ private StarTreeFieldConfiguration.StarTreeBuildMode readBuildMode() throws IOException {
+ return StarTreeFieldConfiguration.StarTreeBuildMode.fromBuildModeOrdinal(meta.readByte());
+ }
+
+ private long readDataStartFilePointer() throws IOException {
+ return meta.readVLong();
+ }
+
+ private long readDataLength() throws IOException {
+ return meta.readVLong();
+ }
+
+ /**
+ * Returns the name of the star-tree field.
+ *
+ * @return star-tree field name
+ */
+ public String getStarTreeFieldName() {
+ return starTreeFieldName;
+ }
+
+ /**
+ * Returns the type of the star tree field.
+ *
+ * @return star-tree field type
+ */
+ public String getStarTreeFieldType() {
+ return starTreeFieldType;
+ }
+
+ /**
+ * Returns the list of dimension field numbers.
+ *
+ * @return star-tree dimension field numbers
+ */
+ public List getDimensionFields() {
+ return dimensionFields;
+ }
+
+ /**
+ * Returns the list of metric entries.
+ *
+ * @return star-tree metric entries
+ */
+ public List getMetricEntries() {
+ return metricEntries;
+ }
+
+ /**
+ * Returns the aggregated document count for the star-tree.
+ *
+ * @return the aggregated document count for the star-tree.
+ */
+ public Integer getSegmentAggregatedDocCount() {
+ return segmentAggregatedDocCount;
+ }
+
+ /**
+ * Returns the max leaf docs for the star-tree.
+ *
+ * @return the max leaf docs.
+ */
+ public Integer getMaxLeafDocs() {
+ return maxLeafDocs;
+ }
+
+ /**
+ * Returns the set of dimensions for which star node will not be created in the star-tree.
+ *
+ * @return the set of dimensions.
+ */
+ public Set getSkipStarNodeCreationInDims() {
+ return skipStarNodeCreationInDims;
+ }
+
+ /**
+ * Returns the build mode for the star-tree.
+ *
+ * @return the star-tree build mode.
+ */
+ public StarTreeFieldConfiguration.StarTreeBuildMode getStarTreeBuildMode() {
+ return starTreeBuildMode;
+ }
+
+ /**
+ * Returns the file pointer to the start of the star-tree data.
+ *
+ * @return start file pointer for star-tree data
+ */
+ public long getDataStartFilePointer() {
+ return dataStartFilePointer;
+ }
+
+ /**
+ * Returns the length of star-tree data
+ *
+ * @return star-tree length
+ */
+ public long getDataLength() {
+ return dataLength;
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/package-info.java
new file mode 100644
index 0000000000000..a2480f03c4b5a
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/meta/package-info.java
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/**
+ * Meta package for star tree
+ *
+ * @opensearch.experimental
+ */
+package org.opensearch.index.compositeindex.datacube.startree.fileformats.meta;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/package-info.java
new file mode 100644
index 0000000000000..917327757fc9b
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/package-info.java
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/**
+ * File formats for star tree
+ *
+ * @opensearch.experimental
+ */
+package org.opensearch.index.compositeindex.datacube.startree.fileformats;
diff --git a/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexValues.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/CompositeIndexValues.java
similarity index 86%
rename from server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexValues.java
rename to server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/CompositeIndexValues.java
index f8848aceab343..3c5c6b71849f2 100644
--- a/server/src/main/java/org/opensearch/index/codec/composite/CompositeIndexValues.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/CompositeIndexValues.java
@@ -6,7 +6,7 @@
* compatible open source license.
*/
-package org.opensearch.index.codec.composite;
+package org.opensearch.index.compositeindex.datacube.startree.index;
import org.opensearch.common.annotation.ExperimentalApi;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/StarTreeValues.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/StarTreeValues.java
new file mode 100644
index 0000000000000..9b487c36fdfb1
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/StarTreeValues.java
@@ -0,0 +1,166 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube.startree.index;
+
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.store.IndexInput;
+import org.opensearch.common.annotation.ExperimentalApi;
+import org.opensearch.index.codec.composite.DocValuesProvider;
+import org.opensearch.index.compositeindex.CompositeIndexMetadata;
+import org.opensearch.index.compositeindex.datacube.Dimension;
+import org.opensearch.index.compositeindex.datacube.Metric;
+import org.opensearch.index.compositeindex.datacube.ReadDimension;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeFieldConfiguration;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.MetricEntry;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.StarTreeMetadata;
+import org.opensearch.index.compositeindex.datacube.startree.node.StarTree;
+import org.opensearch.index.compositeindex.datacube.startree.node.StarTreeNode;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.opensearch.index.codec.composite.composite99.Composite99DocValuesReader.getSortedNumericDocValues;
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.SEGMENT_DOCS_COUNT;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeDimensionsDocValues;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.fullyQualifiedFieldNameForStarTreeMetricsDocValues;
+
+/**
+ * Concrete class that holds the star tree associated values from the segment
+ *
+ * @opensearch.experimental
+ */
+@ExperimentalApi
+public class StarTreeValues implements CompositeIndexValues {
+ private final StarTreeField starTreeField;
+ private final StarTreeNode root;
+ private final Map dimensionDocValuesIteratorMap;
+ private final Map metricDocValuesIteratorMap;
+ private final Map attributes;
+
+ public StarTreeValues(
+ StarTreeField starTreeField,
+ StarTreeNode root,
+ Map dimensionDocValuesIteratorMap,
+ Map metricDocValuesIteratorMap,
+ Map attributes
+ ) {
+ this.starTreeField = starTreeField;
+ this.root = root;
+ this.dimensionDocValuesIteratorMap = dimensionDocValuesIteratorMap;
+ this.metricDocValuesIteratorMap = metricDocValuesIteratorMap;
+ this.attributes = attributes;
+ }
+
+ public StarTreeValues(
+ CompositeIndexMetadata compositeIndexMetadata,
+ IndexInput compositeIndexIn,
+ DocValuesProvider compositeDocValuesProducer
+ ) throws IOException {
+
+ StarTreeMetadata starTreeMetadata = (StarTreeMetadata) compositeIndexMetadata;
+
+ // build skip star node dimensions
+ Set skipStarNodeCreationInDims = starTreeMetadata.getSkipStarNodeCreationInDims();
+
+ // build dimensions
+ List readDimensions = new ArrayList<>();
+ for (String dimension : starTreeMetadata.getDimensionFields()) {
+ readDimensions.add(new ReadDimension(dimension));
+ }
+
+ // build metrics
+ Map starTreeMetricMap = new LinkedHashMap<>();
+ for (MetricEntry metricEntry : starTreeMetadata.getMetricEntries()) {
+ String metricName = metricEntry.getMetricFieldName();
+ Metric metric = starTreeMetricMap.computeIfAbsent(metricName, field -> new Metric(field, new ArrayList<>()));
+ metric.getMetrics().add(metricEntry.getMetricStat());
+ }
+ List starTreeMetrics = new ArrayList<>(starTreeMetricMap.values());
+
+ // star-tree field
+ this.starTreeField = new StarTreeField(
+ starTreeMetadata.getCompositeFieldName(),
+ readDimensions,
+ starTreeMetrics,
+ new StarTreeFieldConfiguration(
+ starTreeMetadata.getMaxLeafDocs(),
+ skipStarNodeCreationInDims,
+ starTreeMetadata.getStarTreeBuildMode()
+ )
+ );
+
+ StarTree starTree = new StarTree(compositeIndexIn, starTreeMetadata);
+ this.root = starTree.getRoot();
+
+ // get doc id set iterators for metrics and dimensions
+ dimensionDocValuesIteratorMap = new LinkedHashMap<>();
+ metricDocValuesIteratorMap = new LinkedHashMap<>();
+
+ // get doc id set iterators for dimensions
+ for (String dimension : starTreeMetadata.getDimensionFields()) {
+ dimensionDocValuesIteratorMap.put(
+ dimension,
+ getSortedNumericDocValues(
+ compositeDocValuesProducer.getSortedNumeric(
+ fullyQualifiedFieldNameForStarTreeDimensionsDocValues(starTreeField.getName(), dimension)
+ )
+ )
+ );
+ }
+
+ // get doc id set iterators for metrics
+ for (MetricEntry metricEntry : starTreeMetadata.getMetricEntries()) {
+ String metricFullName = fullyQualifiedFieldNameForStarTreeMetricsDocValues(
+ starTreeField.getName(),
+ metricEntry.getMetricFieldName(),
+ metricEntry.getMetricStat().getTypeName()
+ );
+ metricDocValuesIteratorMap.put(
+ metricFullName,
+ getSortedNumericDocValues(compositeDocValuesProducer.getSortedNumeric(metricFullName))
+ );
+ }
+
+ // create star-tree attributes map
+ attributes = new HashMap<>();
+ attributes.put(SEGMENT_DOCS_COUNT, String.valueOf(starTreeMetadata.getSegmentAggregatedDocCount()));
+
+ }
+
+ @Override
+ public CompositeIndexValues getValues() {
+ return this;
+ }
+
+ public StarTreeField getStarTreeField() {
+ return starTreeField;
+ }
+
+ public StarTreeNode getRoot() {
+ return root;
+ }
+
+ public Map getDimensionDocValuesIteratorMap() {
+ return dimensionDocValuesIteratorMap;
+ }
+
+ public Map getMetricDocValuesIteratorMap() {
+ return metricDocValuesIteratorMap;
+ }
+
+ public Map getAttributes() {
+ return attributes;
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/package-info.java
new file mode 100644
index 0000000000000..06029042ab407
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/index/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+/**
+ * Classes responsible for handling all star tree values from the segment
+ */
+package org.opensearch.index.compositeindex.datacube.startree.index;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/FixedLengthStarTreeNode.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/FixedLengthStarTreeNode.java
new file mode 100644
index 0000000000000..8159d2039121c
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/FixedLengthStarTreeNode.java
@@ -0,0 +1,186 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+package org.opensearch.index.compositeindex.datacube.startree.node;
+
+import org.apache.lucene.store.RandomAccessInput;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.ALL;
+
+/**
+ * Fixed Length implementation of {@link StarTreeNode}
+ *
+ * @opensearch.experimental
+ */
+public class FixedLengthStarTreeNode implements StarTreeNode {
+ public static final int NUM_INT_SERIALIZABLE_FIELDS = 6;
+ public static final int NUM_LONG_SERIALIZABLE_FIELDS = 1;
+ public static final int NUM_BYTE_SERIALIZABLE_FIELDS = 1;
+ public static final long SERIALIZABLE_DATA_SIZE_IN_BYTES = (Integer.BYTES * NUM_INT_SERIALIZABLE_FIELDS) + (Long.BYTES
+ * NUM_LONG_SERIALIZABLE_FIELDS) + (NUM_BYTE_SERIALIZABLE_FIELDS * Byte.BYTES);
+ private static final int DIMENSION_ID_OFFSET = 0;
+ private static final int DIMENSION_VALUE_OFFSET = DIMENSION_ID_OFFSET + Integer.BYTES;
+ private static final int START_DOC_ID_OFFSET = DIMENSION_VALUE_OFFSET + Long.BYTES;
+ private static final int END_DOC_ID_OFFSET = START_DOC_ID_OFFSET + Integer.BYTES;
+ private static final int AGGREGATE_DOC_ID_OFFSET = END_DOC_ID_OFFSET + Integer.BYTES;
+ private static final int STAR_NODE_TYPE_OFFSET = AGGREGATE_DOC_ID_OFFSET + Integer.BYTES;
+ private static final int FIRST_CHILD_ID_OFFSET = STAR_NODE_TYPE_OFFSET + Byte.BYTES;
+ private static final int LAST_CHILD_ID_OFFSET = FIRST_CHILD_ID_OFFSET + Integer.BYTES;
+
+ public static final int INVALID_ID = -1;
+
+ private final int nodeId;
+ private final int firstChildId;
+
+ RandomAccessInput in;
+
+ public FixedLengthStarTreeNode(RandomAccessInput in, int nodeId) throws IOException {
+ this.in = in;
+ this.nodeId = nodeId;
+ firstChildId = getInt(FIRST_CHILD_ID_OFFSET);
+ }
+
+ private int getInt(int fieldOffset) throws IOException {
+ return in.readInt(nodeId * SERIALIZABLE_DATA_SIZE_IN_BYTES + fieldOffset);
+ }
+
+ private long getLong(int fieldOffset) throws IOException {
+ return in.readLong(nodeId * SERIALIZABLE_DATA_SIZE_IN_BYTES + fieldOffset);
+ }
+
+ private byte getByte(int fieldOffset) throws IOException {
+ return in.readByte(nodeId * SERIALIZABLE_DATA_SIZE_IN_BYTES + fieldOffset);
+ }
+
+ @Override
+ public int getDimensionId() throws IOException {
+ return getInt(DIMENSION_ID_OFFSET);
+ }
+
+ @Override
+ public long getDimensionValue() throws IOException {
+ return getLong(DIMENSION_VALUE_OFFSET);
+ }
+
+ @Override
+ public int getChildDimensionId() throws IOException {
+ if (firstChildId == INVALID_ID) {
+ return INVALID_ID;
+ } else {
+ return in.readInt(firstChildId * SERIALIZABLE_DATA_SIZE_IN_BYTES);
+ }
+ }
+
+ @Override
+ public int getStartDocId() throws IOException {
+ return getInt(START_DOC_ID_OFFSET);
+ }
+
+ @Override
+ public int getEndDocId() throws IOException {
+ return getInt(END_DOC_ID_OFFSET);
+ }
+
+ @Override
+ public int getAggregatedDocId() throws IOException {
+ return getInt(AGGREGATE_DOC_ID_OFFSET);
+ }
+
+ @Override
+ public int getNumChildren() throws IOException {
+ if (firstChildId == INVALID_ID) {
+ return 0;
+ } else {
+ return getInt(LAST_CHILD_ID_OFFSET) - firstChildId + 1;
+ }
+ }
+
+ @Override
+ public boolean isLeaf() {
+ return firstChildId == INVALID_ID;
+ }
+
+ @Override
+ public byte getStarTreeNodeType() throws IOException {
+ return getByte(STAR_NODE_TYPE_OFFSET);
+ }
+
+ @Override
+ public StarTreeNode getChildForDimensionValue(long dimensionValue, boolean isStar) throws IOException {
+ // there will be no children for leaf nodes
+ if (isLeaf()) {
+ return null;
+ }
+
+ // Specialize star node for performance
+ if (isStar) {
+ return handleStarNode();
+ }
+
+ return binarySearchChild(dimensionValue);
+ }
+
+ private FixedLengthStarTreeNode handleStarNode() throws IOException {
+ FixedLengthStarTreeNode firstNode = new FixedLengthStarTreeNode(in, firstChildId);
+ if (firstNode.getDimensionValue() == ALL) {
+ return firstNode;
+ } else {
+ return null;
+ }
+ }
+
+ private FixedLengthStarTreeNode binarySearchChild(long dimensionValue) throws IOException {
+ // Binary search to find child node
+ int low = firstChildId;
+ int high = getInt(LAST_CHILD_ID_OFFSET);
+
+ while (low <= high) {
+ int mid = low + (high - low) / 2;
+ FixedLengthStarTreeNode midNode = new FixedLengthStarTreeNode(in, mid);
+ long midNodeDimensionValue = midNode.getDimensionValue();
+
+ if (midNodeDimensionValue == dimensionValue) {
+ return midNode;
+ } else if (midNodeDimensionValue < dimensionValue) {
+ low = mid + 1;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Iterator getChildrenIterator() throws IOException {
+ return new Iterator<>() {
+ private int currentChildId = firstChildId;
+ private final int lastChildId = getInt(LAST_CHILD_ID_OFFSET);
+
+ @Override
+ public boolean hasNext() {
+ return currentChildId <= lastChildId;
+ }
+
+ @Override
+ public FixedLengthStarTreeNode next() {
+ try {
+ return new FixedLengthStarTreeNode(in, currentChildId++);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/TreeNode.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/InMemoryTreeNode.java
similarity index 76%
rename from server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/TreeNode.java
rename to server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/InMemoryTreeNode.java
index a5d59a2602633..20f7dcf184391 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/TreeNode.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/InMemoryTreeNode.java
@@ -5,12 +5,14 @@
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
-package org.opensearch.index.compositeindex.datacube.startree.utils;
+package org.opensearch.index.compositeindex.datacube.startree.node;
import org.opensearch.common.annotation.ExperimentalApi;
import java.util.Map;
+import static org.opensearch.index.compositeindex.datacube.startree.utils.StarTreeUtils.ALL;
+
/**
* /**
* Represents a node in a tree data structure, specifically designed for a star-tree implementation.
@@ -19,9 +21,7 @@
* @opensearch.experimental
*/
@ExperimentalApi
-public class TreeNode {
-
- public static final int ALL = -1;
+public class InMemoryTreeNode {
/**
* The dimension id for the dimension (field) associated with this star-tree node.
@@ -54,16 +54,21 @@ public class TreeNode {
public long dimensionValue = ALL;
/**
- * A flag indicating whether this node is a star node (a node that represents an aggregation of all dimensions).
+ * A byte indicating whether the node is star node, null node or default node (with dimension value present).
*/
- public boolean isStarNode = false;
+ public byte nodeType = 0;
/**
* A map containing the child nodes of this star-tree node, keyed by their dimension id.
*/
- public Map children;
+ public Map children;
public long getDimensionValue() {
return dimensionValue;
}
+
+ public byte getNodeType() {
+ return nodeType;
+ }
+
}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTree.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTree.java
new file mode 100644
index 0000000000000..4ed3c3ec9febe
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTree.java
@@ -0,0 +1,65 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+package org.opensearch.index.compositeindex.datacube.startree.node;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.RandomAccessInput;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.data.StarTreeDataWriter;
+import org.opensearch.index.compositeindex.datacube.startree.fileformats.meta.StarTreeMetadata;
+
+import java.io.IOException;
+
+import static org.opensearch.index.compositeindex.CompositeIndexConstants.COMPOSITE_FIELD_MARKER;
+import static org.opensearch.index.compositeindex.datacube.startree.fileformats.StarTreeWriter.VERSION_CURRENT;
+
+/**
+ * Off heap implementation of the star-tree.
+ *
+ * @opensearch.experimental
+ */
+public class StarTree {
+ private static final Logger logger = LogManager.getLogger(StarTree.class);
+ private final FixedLengthStarTreeNode root;
+ private final Integer numNodes;
+
+ public StarTree(IndexInput data, StarTreeMetadata starTreeMetadata) throws IOException {
+ long magicMarker = data.readLong();
+ if (COMPOSITE_FIELD_MARKER != magicMarker) {
+ logger.error("Invalid magic marker");
+ throw new IOException("Invalid magic marker");
+ }
+ int version = data.readInt();
+ if (VERSION_CURRENT != version) {
+ logger.error("Invalid star tree version");
+ throw new IOException("Invalid version");
+ }
+ numNodes = data.readInt(); // num nodes
+
+ RandomAccessInput in = data.randomAccessSlice(
+ StarTreeDataWriter.computeStarTreeDataHeaderByteSize(),
+ starTreeMetadata.getDataLength() - StarTreeDataWriter.computeStarTreeDataHeaderByteSize()
+ );
+ root = new FixedLengthStarTreeNode(in, 0);
+ }
+
+ public StarTreeNode getRoot() {
+ return root;
+ }
+
+ /**
+ * Returns the number of nodes in star-tree
+ *
+ * @return number of nodes in te star-tree
+ */
+ public Integer getNumNodes() {
+ return numNodes;
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNode.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNode.java
index 59522ffa4be89..dd9d301096f44 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNode.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNode.java
@@ -20,7 +20,6 @@
*/
@ExperimentalApi
public interface StarTreeNode {
- long ALL = -1l;
/**
* Returns the dimension ID of the current star-tree node.
@@ -86,12 +85,20 @@ public interface StarTreeNode {
boolean isLeaf();
/**
- * Checks if the current node is a star node.
+ * Determines the type of the current node in the Star Tree index structure.
*
- * @return true if the node is a star node, false otherwise
- * @throws IOException if an I/O error occurs while reading the star node status
+ *
The node type can be one of the following:
+ *
+ *
Star Node: Represented by the value -2.
+ *
Null Node: Represented by the value -1.
+ *
Default Node: Represented by the value 0.
+ *
+ * @see StarTreeNodeType
+ *
+ * @return The type of the current node, represented by the corresponding integer value (-2, -1, or 0).
+ * @throws IOException if an I/O error occurs while reading the node type
*/
- boolean isStarNode() throws IOException;
+ byte getStarTreeNodeType() throws IOException;
/**
* Returns the child star-tree node for the given dimension value.
@@ -100,7 +107,7 @@ public interface StarTreeNode {
* @return the child node for the given dimension value or null if child is not present
* @throws IOException if an I/O error occurs while retrieving the child node
*/
- StarTreeNode getChildForDimensionValue(long dimensionValue) throws IOException;
+ StarTreeNode getChildForDimensionValue(long dimensionValue, boolean isStar) throws IOException;
/**
* Returns an iterator over the children of the current star-tree node.
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNodeType.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNodeType.java
new file mode 100644
index 0000000000000..2dcec37322778
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNodeType.java
@@ -0,0 +1,103 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+
+package org.opensearch.index.compositeindex.datacube.startree.node;
+
+/**
+ * Represents the different types of nodes in a StarTree data structure.
+ *
+ *
+ * In order to handle different node types, we use a byte value to represent the node type.
+ * This enum provides a convenient way to map byte values to their corresponding node types.
+ *
+ *
+ * Star and Null Nodes are represented as special cases. Default is the general case.
+ * Star and null nodes are represented with negative ordinal values to ensure that they are
+ * sorted before the default nodes, which are sorted based on their dimension values.
+ *
+ *
+ * The node type can be one of the following:
+ *
+ *
Star Node: Represented by the value -2. A star node is a special node that represents
+ * all possible values for a dimension.
+ *
Null Node: Represented by the value -1. A null node indicates the absence of any value
+ * for a dimension.
+ *
Default Node: Represented by the value 0. A default node represents a node with an
+ * actual dimension value.
+ *
+ *
+ * By default, we want to consider nodes as default node.
+ *
+ * @opensearch.experimental
+ * @see StarTreeNode
+ */
+public enum StarTreeNodeType {
+
+ /**
+ * Represents a star node type.
+ *
+ */
+ STAR("star", (byte) -2),
+
+ /**
+ * Represents a null node type.
+ */
+ NULL("null", (byte) -1),
+
+ /**
+ * Represents a default node type.
+ */
+ DEFAULT("default", (byte) 0);
+
+ private final String name;
+ private final byte value;
+
+ /**
+ * Constructs a new StarTreeNodeType with the given name and value.
+ *
+ * @param name the name of the node type
+ * @param value the value associated with the node type
+ */
+ StarTreeNodeType(String name, byte value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ /**
+ * Returns the name of the node type.
+ *
+ * @return the name of the node type
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the value associated with the node type.
+ *
+ * @return the value associated with the node type
+ */
+ public byte getValue() {
+ return value;
+ }
+
+ /**
+ * Returns the StarTreeNodeType enum constant with the specified value.
+ *
+ * @param value the value of the enum constant to return
+ * @return the enum constant with the specified value, or null if no such constant exists
+ */
+ public static StarTreeNodeType fromValue(byte value) {
+ for (StarTreeNodeType nodeType : StarTreeNodeType.values()) {
+ if (nodeType.getValue() == value) {
+ return nodeType;
+ }
+ }
+ return null;
+ }
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/package-info.java
index 516d5b5a012ab..19d12bc6318d7 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/package-info.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/package-info.java
@@ -8,5 +8,7 @@
/**
* Holds classes associated with star tree node
+ *
+ * @opensearch.experimental
*/
package org.opensearch.index.compositeindex.datacube.startree.node;
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/SequentialDocValuesIterator.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/SequentialDocValuesIterator.java
index 400d7a1c00104..bf1f1d52b4eee 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/SequentialDocValuesIterator.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/SequentialDocValuesIterator.java
@@ -9,6 +9,7 @@
package org.opensearch.index.compositeindex.datacube.startree.utils;
+import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.search.DocIdSetIterator;
import org.opensearch.common.annotation.ExperimentalApi;
@@ -28,6 +29,11 @@ public class SequentialDocValuesIterator {
*/
private final DocIdSetIterator docIdSetIterator;
+ /**
+ * The value associated with the latest document.
+ */
+ private Long docValue;
+
/**
* The id of the latest document.
*/
@@ -42,15 +48,50 @@ public SequentialDocValuesIterator(DocIdSetIterator docIdSetIterator) {
this.docIdSetIterator = docIdSetIterator;
}
+ /**
+ * Constructs a new SequentialDocValuesIterator instance with an empty sorted numeric.
+ *
+ */
+ public SequentialDocValuesIterator() {
+ this.docIdSetIterator = DocValues.emptySortedNumeric();
+ }
+
+ /**
+ * Returns the value associated with the latest document.
+ *
+ * @return the value associated with the latest document
+ */
+ public Long getDocValue() {
+ return docValue;
+ }
+
+ /**
+ * Sets the value associated with the latest document.
+ *
+ * @param docValue the value to be associated with the latest document
+ */
+ public void setDocValue(Long docValue) {
+ this.docValue = docValue;
+ }
+
/**
* Returns the id of the latest document.
*
* @return the id of the latest document
*/
- int getDocId() {
+ public int getDocId() {
return docId;
}
+ /**
+ * Sets the id of the latest document.
+ *
+ * @param docId the ID of the latest document
+ */
+ public void setDocId(int docId) {
+ this.docId = docId;
+ }
+
/**
* Returns the DocIdSetIterator associated with this instance.
*
@@ -65,7 +106,7 @@ public int nextDoc(int currentDocId) throws IOException {
if (docId >= currentDocId) {
return docId;
}
- docId = this.docIdSetIterator.nextDoc();
+ setDocId(this.docIdSetIterator.nextDoc());
return docId;
}
@@ -81,7 +122,12 @@ public Long value(int currentDocId) throws IOException {
if (docId == DocIdSetIterator.NO_MORE_DOCS || docId != currentDocId) {
return null;
}
- return sortedNumericDocValues.nextValue();
+ if (docValue == null) {
+ docValue = sortedNumericDocValues.nextValue();
+ }
+ Long nextValue = docValue;
+ docValue = null;
+ return nextValue;
} else {
throw new IllegalStateException("Unsupported Iterator requested for SequentialDocValuesIterator");
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/StarTreeUtils.java b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/StarTreeUtils.java
new file mode 100644
index 0000000000000..dc155df4eafca
--- /dev/null
+++ b/server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/utils/StarTreeUtils.java
@@ -0,0 +1,111 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ */
+package org.opensearch.index.compositeindex.datacube.startree.utils;
+
+import org.apache.lucene.index.DocValuesType;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.IndexOptions;
+import org.apache.lucene.index.VectorEncoding;
+import org.apache.lucene.index.VectorSimilarityFunction;
+import org.opensearch.index.compositeindex.datacube.startree.aggregators.MetricAggregatorInfo;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Util class for building star tree
+ *
+ * @opensearch.experimental
+ */
+public class StarTreeUtils {
+
+ private StarTreeUtils() {}
+
+ public static final int ALL = -1;
+
+ /**
+ * The suffix appended to dimension field names in the Star Tree index.
+ */
+ public static final String DIMENSION_SUFFIX = "dim";
+
+ /**
+ * The suffix appended to metric field names in the Star Tree index.
+ */
+ public static final String METRIC_SUFFIX = "metric";
+
+ /**
+ * Returns the full field name for a dimension in the star-tree index.
+ *
+ * @param starTreeFieldName star-tree field name
+ * @param dimensionName name of the dimension
+ * @return full field name for the dimension in the star-tree index
+ */
+ public static String fullyQualifiedFieldNameForStarTreeDimensionsDocValues(String starTreeFieldName, String dimensionName) {
+ return starTreeFieldName + "_" + dimensionName + "_" + DIMENSION_SUFFIX;
+ }
+
+ /**
+ * Returns the full field name for a metric in the star-tree index.
+ *
+ * @param starTreeFieldName star-tree field name
+ * @param fieldName name of the metric field
+ * @param metricName name of the metric
+ * @return full field name for the metric in the star-tree index
+ */
+ public static String fullyQualifiedFieldNameForStarTreeMetricsDocValues(String starTreeFieldName, String fieldName, String metricName) {
+ return MetricAggregatorInfo.toFieldName(starTreeFieldName, fieldName, metricName) + "_" + METRIC_SUFFIX;
+ }
+
+ /**
+ * Get field infos from field names
+ *
+ * @param fields field names
+ * @return field infos
+ */
+ public static FieldInfo[] getFieldInfoList(List fields) {
+ FieldInfo[] fieldInfoList = new FieldInfo[fields.size()];
+
+ // field number is not really used. We depend on unique field names to get the desired iterator
+ int fieldNumber = 0;
+
+ for (String fieldName : fields) {
+ fieldInfoList[fieldNumber] = getFieldInfo(fieldName, fieldNumber);
+ fieldNumber++;
+ }
+ return fieldInfoList;
+ }
+
+ /**
+ * Get new field info instance for a given field name and field number
+ * @param fieldName name of the field
+ * @param fieldNumber number of the field
+ * @return new field info instance
+ */
+ public static FieldInfo getFieldInfo(String fieldName, int fieldNumber) {
+ return new FieldInfo(
+ fieldName,
+ fieldNumber,
+ false,
+ false,
+ true,
+ IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS,
+ DocValuesType.SORTED_NUMERIC,
+ -1,
+ Collections.emptyMap(),
+ 0,
+ 0,
+ 0,
+ 0,
+ VectorEncoding.FLOAT32,
+ VectorSimilarityFunction.EUCLIDEAN,
+ false,
+ false
+ );
+ }
+
+}
diff --git a/server/src/main/java/org/opensearch/index/compositeindex/package-info.java b/server/src/main/java/org/opensearch/index/compositeindex/package-info.java
index 59f18efec26b1..9a88f88d9850a 100644
--- a/server/src/main/java/org/opensearch/index/compositeindex/package-info.java
+++ b/server/src/main/java/org/opensearch/index/compositeindex/package-info.java
@@ -8,6 +8,7 @@
/**
* Core classes for handling composite indices.
- * @opensearch.experimental
+ *
+ * @opensearch.experimental
*/
package org.opensearch.index.compositeindex;
diff --git a/server/src/main/resources/META-INF/services/org.apache.lucene.codecs.Codec b/server/src/main/resources/META-INF/services/org.apache.lucene.codecs.Codec
index e030a813373c1..f51452c57f975 100644
--- a/server/src/main/resources/META-INF/services/org.apache.lucene.codecs.Codec
+++ b/server/src/main/resources/META-INF/services/org.apache.lucene.codecs.Codec
@@ -1 +1 @@
-org.opensearch.index.codec.composite.Composite99Codec
+org.opensearch.index.codec.composite.composite99.Composite99Codec
diff --git a/server/src/test/java/org/opensearch/index/codec/CodecTests.java b/server/src/test/java/org/opensearch/index/codec/CodecTests.java
index 7146b7dc51753..bbf98b5c32918 100644
--- a/server/src/test/java/org/opensearch/index/codec/CodecTests.java
+++ b/server/src/test/java/org/opensearch/index/codec/CodecTests.java
@@ -48,7 +48,7 @@
import org.opensearch.env.Environment;
import org.opensearch.index.IndexSettings;
import org.opensearch.index.analysis.IndexAnalyzers;
-import org.opensearch.index.codec.composite.Composite99Codec;
+import org.opensearch.index.codec.composite.composite99.Composite99Codec;
import org.opensearch.index.engine.EngineConfig;
import org.opensearch.index.mapper.MapperService;
import org.opensearch.index.similarity.SimilarityService;
diff --git a/server/src/test/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeDocValuesFormatTests.java b/server/src/test/java/org/opensearch/index/codec/composite99/datacube/startree/StarTreeDocValuesFormatTests.java
similarity index 54%
rename from server/src/test/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeDocValuesFormatTests.java
rename to server/src/test/java/org/opensearch/index/codec/composite99/datacube/startree/StarTreeDocValuesFormatTests.java
index 049d91bc42d9c..c44c4451f859f 100644
--- a/server/src/test/java/org/opensearch/index/codec/composite/datacube/startree/StarTreeDocValuesFormatTests.java
+++ b/server/src/test/java/org/opensearch/index/codec/composite99/datacube/startree/StarTreeDocValuesFormatTests.java
@@ -6,7 +6,9 @@
* compatible open source license.
*/
-package org.opensearch.index.codec.composite.datacube.startree;
+package org.opensearch.index.codec.composite99.datacube.startree;
+
+import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -14,32 +16,56 @@
import org.apache.lucene.codecs.lucene99.Lucene99Codec;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.SortedNumericDocValuesField;
+import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.SegmentReader;
import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.index.BaseDocValuesFormatTestCase;
import org.apache.lucene.tests.index.RandomIndexWriter;
import org.apache.lucene.tests.util.LuceneTestCase;
+import org.apache.lucene.tests.util.TestUtil;
import org.opensearch.Version;
import org.opensearch.cluster.ClusterModule;
import org.opensearch.cluster.metadata.IndexMetadata;
import org.opensearch.common.CheckedConsumer;
+import org.opensearch.common.Rounding;
+import org.opensearch.common.lucene.Lucene;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.FeatureFlags;
import org.opensearch.common.xcontent.XContentFactory;
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.core.xcontent.XContentBuilder;
import org.opensearch.index.MapperTestUtils;
-import org.opensearch.index.codec.composite.Composite99Codec;
+import org.opensearch.index.codec.composite.CompositeIndexFieldInfo;
+import org.opensearch.index.codec.composite.CompositeIndexReader;
+import org.opensearch.index.codec.composite.composite99.Composite99Codec;
+import org.opensearch.index.compositeindex.datacube.DateDimension;
+import org.opensearch.index.compositeindex.datacube.Dimension;
+import org.opensearch.index.compositeindex.datacube.Metric;
+import org.opensearch.index.compositeindex.datacube.MetricStat;
+import org.opensearch.index.compositeindex.datacube.NumericDimension;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeDocument;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeField;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeFieldConfiguration;
+import org.opensearch.index.compositeindex.datacube.startree.StarTreeTestUtils;
+import org.opensearch.index.compositeindex.datacube.startree.aggregators.numerictype.StarTreeNumericType;
+import org.opensearch.index.compositeindex.datacube.startree.index.StarTreeValues;
import org.opensearch.index.mapper.MapperService;
+import org.opensearch.index.mapper.StarTreeMapper;
import org.opensearch.indices.IndicesModule;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import static org.opensearch.common.util.FeatureFlags.STAR_TREE_INDEX;
+import static org.opensearch.index.compositeindex.datacube.startree.StarTreeTestUtils.assertStarTreeDocuments;
/**
* Star tree doc values Lucene tests
@@ -47,6 +73,19 @@
@LuceneTestCase.SuppressSysoutChecks(bugUrl = "we log a lot on purpose")
public class StarTreeDocValuesFormatTests extends BaseDocValuesFormatTestCase {
MapperService mapperService = null;
+ StarTreeFieldConfiguration.StarTreeBuildMode buildMode;
+
+ public StarTreeDocValuesFormatTests(StarTreeFieldConfiguration.StarTreeBuildMode buildMode) {
+ this.buildMode = buildMode;
+ }
+
+ @ParametersFactory
+ public static Collection