Skip to content

Commit fcf5c35

Browse files
authored
[Backport 2.x] Extensible design to add new query and field type support for Star Tree (#17173)
* Extensible design to add new query and field type support for Star Tree (#17137) --------- Signed-off-by: expani <anijainc@amazon.com> * Merge conflict resolution for Java11 Signed-off-by: expani <anijainc@amazon.com> * Added back StarTreeQryCtx methods in SearchCtx to make API Compatibility pass Signed-off-by: expani <anijainc@amazon.com> * Java11 Compatible changes Signed-off-by: expani <anijainc@amazon.com> --------- Signed-off-by: expani <anijainc@amazon.com>
1 parent 73eb6c7 commit fcf5c35

38 files changed

+3054
-718
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3737
- Introduce Template query ([#16818](https://github.com/opensearch-project/OpenSearch/pull/16818))
3838
- Propagate the sourceIncludes and excludes fields from fetchSourceContext to FieldsVisitor. ([#17080](https://github.com/opensearch-project/OpenSearch/pull/17080))
3939
- [Star Tree] [Search] Resolving Date histogram with metric aggregation using star-tree ([#16674](https://github.com/opensearch-project/OpenSearch/pull/16674))
40+
- [Star Tree] [Search] Extensible design to support different query and field types ([#17137](https://github.com/opensearch-project/OpenSearch/pull/17137))
4041

4142
### Dependencies
4243
- Bump `com.google.cloud:google-cloud-core-http` from 2.23.0 to 2.47.0 ([#16504](https://github.com/opensearch-project/OpenSearch/pull/16504))

server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/fileformats/node/FixedLengthStarTreeNode.java

+115-8
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.apache.lucene.store.RandomAccessInput;
1111
import org.opensearch.index.compositeindex.datacube.startree.node.StarTreeNode;
1212
import org.opensearch.index.compositeindex.datacube.startree.node.StarTreeNodeType;
13+
import org.opensearch.search.startree.StarTreeNodeCollector;
1314

1415
import java.io.IOException;
1516
import java.io.UncheckedIOException;
@@ -192,15 +193,15 @@ public StarTreeNode getChildStarNode() throws IOException {
192193
}
193194

194195
@Override
195-
public StarTreeNode getChildForDimensionValue(Long dimensionValue) throws IOException {
196+
public StarTreeNode getChildForDimensionValue(Long dimensionValue, StarTreeNode lastMatchedChild) throws IOException {
196197
// there will be no children for leaf nodes
197198
if (isLeaf()) {
198199
return null;
199200
}
200201

201202
StarTreeNode resultStarTreeNode = null;
202203
if (null != dimensionValue) {
203-
resultStarTreeNode = binarySearchChild(dimensionValue);
204+
resultStarTreeNode = binarySearchChild(dimensionValue, lastMatchedChild);
204205
}
205206
return resultStarTreeNode;
206207
}
@@ -240,21 +241,29 @@ private static FixedLengthStarTreeNode matchStarTreeNodeTypeOrNull(FixedLengthSt
240241
* @return The child node if found, null otherwise
241242
* @throws IOException If there's an error reading from the input
242243
*/
243-
private FixedLengthStarTreeNode binarySearchChild(long dimensionValue) throws IOException {
244+
private FixedLengthStarTreeNode binarySearchChild(long dimensionValue, StarTreeNode lastMatchedNode) throws IOException {
244245

245246
int low = firstChildId;
246247

247-
// if the current node is star node, increment the low to reduce the search space
248-
if (matchStarTreeNodeTypeOrNull(new FixedLengthStarTreeNode(in, firstChildId), StarTreeNodeType.STAR) != null) {
249-
low++;
250-
}
251-
252248
int high = getInt(LAST_CHILD_ID_OFFSET);
253249
// if the current node is null node, decrement the high to reduce the search space
254250
if (matchStarTreeNodeTypeOrNull(new FixedLengthStarTreeNode(in, high), StarTreeNodeType.NULL) != null) {
255251
high--;
256252
}
257253

254+
if (lastMatchedNode instanceof FixedLengthStarTreeNode) {
255+
int lastMatchedNodeId = ((FixedLengthStarTreeNode) lastMatchedNode).nodeId();
256+
// Start the binary search from node after the last matched as low.
257+
if ((lastMatchedNodeId + 1) <= high) {
258+
low = lastMatchedNodeId + 1;
259+
} else {
260+
return null;
261+
}
262+
} else if (matchStarTreeNodeTypeOrNull(new FixedLengthStarTreeNode(in, low), StarTreeNodeType.STAR) != null) {
263+
// if the current node is star node, increment the low to reduce the search space
264+
low++;
265+
}
266+
258267
while (low <= high) {
259268
int mid = low + (high - low) / 2;
260269
FixedLengthStarTreeNode midNode = new FixedLengthStarTreeNode(in, mid);
@@ -271,6 +280,100 @@ private FixedLengthStarTreeNode binarySearchChild(long dimensionValue) throws IO
271280
return null;
272281
}
273282

283+
@Override
284+
public void collectChildrenInRange(long low, long high, StarTreeNodeCollector collector) throws IOException {
285+
if (low <= high) {
286+
FixedLengthStarTreeNode lowStarTreeNode = binarySearchChild(low, true, null);
287+
if (lowStarTreeNode != null) {
288+
FixedLengthStarTreeNode highStarTreeNode = binarySearchChild(high, false, lowStarTreeNode);
289+
if (highStarTreeNode != null) {
290+
for (int lowNodeId = lowStarTreeNode.nodeId(); lowNodeId <= highStarTreeNode.nodeId(); ++lowNodeId) {
291+
collector.collectStarTreeNode(new FixedLengthStarTreeNode(in, lowNodeId));
292+
}
293+
} else if (lowStarTreeNode.getDimensionValue() <= high) { // Low StarTreeNode is the last default node for that dimension.
294+
collector.collectStarTreeNode(lowStarTreeNode);
295+
}
296+
}
297+
}
298+
}
299+
300+
/**
301+
*
302+
* @param dimensionValue : The dimension to match.
303+
* @param matchNextHighest : If true then we try to return @dimensionValue or the next Highest. Else, we return @dimensionValue or the next Lowest.
304+
* @param lastMatchedNode : If not null, we begin the binary search from the node after this.
305+
* @return : Matched node or null.
306+
* @throws IOException :
307+
*/
308+
private FixedLengthStarTreeNode binarySearchChild(long dimensionValue, boolean matchNextHighest, StarTreeNode lastMatchedNode)
309+
throws IOException {
310+
311+
int low = firstChildId;
312+
int tempLow = low;
313+
int starNodeId, nullNodeId;
314+
starNodeId = nullNodeId = Integer.MIN_VALUE;
315+
316+
// if the current node is star node, increment the tempLow to reduce the search space
317+
if (matchStarTreeNodeTypeOrNull(new FixedLengthStarTreeNode(in, tempLow), StarTreeNodeType.STAR) != null) {
318+
starNodeId = tempLow;
319+
tempLow++;
320+
}
321+
322+
int high = getInt(LAST_CHILD_ID_OFFSET);
323+
int tempHigh = high;
324+
// if the current node is null node, decrement the tempHigh to reduce the search space
325+
if (matchStarTreeNodeTypeOrNull(new FixedLengthStarTreeNode(in, tempHigh), StarTreeNodeType.NULL) != null) {
326+
nullNodeId = tempHigh;
327+
tempHigh--;
328+
}
329+
330+
if (lastMatchedNode instanceof FixedLengthStarTreeNode) {
331+
int lastMatchedNodeId = ((FixedLengthStarTreeNode) lastMatchedNode).nodeId();
332+
// Start the binary search from node after the last matched as low.
333+
if ((lastMatchedNodeId + 1) <= tempHigh) {
334+
tempLow = lastMatchedNodeId + 1;
335+
} else {
336+
return null;
337+
}
338+
}
339+
340+
while (tempLow <= tempHigh) {
341+
int mid = tempLow + (tempHigh - tempLow) / 2;
342+
FixedLengthStarTreeNode midNode = new FixedLengthStarTreeNode(in, mid);
343+
long midDimensionValue = midNode.getDimensionValue();
344+
345+
if (midDimensionValue == dimensionValue) {
346+
return midNode;
347+
} else {
348+
if (midDimensionValue < dimensionValue) { // Going to the right from mid to search next
349+
tempLow = mid + 1;
350+
// We are going out of bounds for this dimension on the right side.
351+
if (tempLow > high || tempLow == nullNodeId) {
352+
return matchNextHighest ? null : midNode;
353+
} else {
354+
FixedLengthStarTreeNode nodeGreaterThanMid = new FixedLengthStarTreeNode(in, tempLow);
355+
if (nodeGreaterThanMid.getDimensionValue() > dimensionValue) {
356+
return matchNextHighest ? nodeGreaterThanMid : midNode;
357+
}
358+
}
359+
} else { // Going to the left from mid to search next
360+
tempHigh = mid - 1;
361+
// We are going out of bounds for this dimension on the left side.
362+
if (tempHigh < low || tempHigh == starNodeId) {
363+
return matchNextHighest ? midNode : null;
364+
} else {
365+
FixedLengthStarTreeNode nodeLessThanMid = new FixedLengthStarTreeNode(in, tempHigh);
366+
if (nodeLessThanMid.getDimensionValue() < dimensionValue) {
367+
return matchNextHighest ? midNode : nodeLessThanMid;
368+
}
369+
}
370+
}
371+
}
372+
}
373+
return null;
374+
375+
}
376+
274377
@Override
275378
public Iterator<FixedLengthStarTreeNode> getChildrenIterator() throws IOException {
276379
return new Iterator<>() {
@@ -297,4 +400,8 @@ public void remove() {
297400
}
298401
};
299402
}
403+
404+
public int nodeId() {
405+
return nodeId;
406+
}
300407
}

server/src/main/java/org/opensearch/index/compositeindex/datacube/startree/node/StarTreeNode.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.opensearch.index.compositeindex.datacube.startree.node;
1010

1111
import org.opensearch.common.annotation.ExperimentalApi;
12+
import org.opensearch.search.startree.StarTreeNodeCollector;
1213

1314
import java.io.IOException;
1415
import java.util.Iterator;
@@ -107,7 +108,27 @@ public interface StarTreeNode {
107108
* @return the child node for the given dimension value or null if child is not present
108109
* @throws IOException if an I/O error occurs while retrieving the child node
109110
*/
110-
StarTreeNode getChildForDimensionValue(Long dimensionValue) throws IOException;
111+
default StarTreeNode getChildForDimensionValue(Long dimensionValue) throws IOException {
112+
return getChildForDimensionValue(dimensionValue, null);
113+
}
114+
115+
/**
116+
* Matches the given @dimensionValue amongst the child default nodes for this node.
117+
* @param dimensionValue : Value to match
118+
* @param lastMatchedChild : If not null, binary search will use this as the start/low
119+
* @return : Matched StarTreeNode or null if not found
120+
* @throws IOException : Any exception in reading the node data from index.
121+
*/
122+
StarTreeNode getChildForDimensionValue(Long dimensionValue, StarTreeNode lastMatchedChild) throws IOException;
123+
124+
/**
125+
* Collects all matching child nodes whose dimension values lie within the range of low and high, both inclusive.
126+
* @param low : Starting of the range ( inclusive )
127+
* @param high : End of the range ( inclusive )
128+
* @param collector : Collector to collect the matched child StarTreeNode's
129+
* @throws IOException : Any exception in reading the node data from index.
130+
*/
131+
void collectChildrenInRange(long low, long high, StarTreeNodeCollector collector) throws IOException;
111132

112133
/**
113134
* Returns the child star node for a node in the star-tree.

0 commit comments

Comments
 (0)