7777import org .opensearch .index .IndexNotFoundException ;
7878import org .opensearch .index .IndexService ;
7979import org .opensearch .index .IndexSettings ;
80+ import org .opensearch .index .codec .composite .CompositeIndexFieldInfo ;
8081import org .opensearch .index .engine .Engine ;
82+ import org .opensearch .index .mapper .CompositeDataCubeFieldType ;
8183import org .opensearch .index .mapper .DerivedFieldResolver ;
8284import org .opensearch .index .mapper .DerivedFieldResolverFactory ;
85+ import org .opensearch .index .mapper .StarTreeMapper ;
8386import org .opensearch .index .query .InnerHitContextBuilder ;
8487import org .opensearch .index .query .MatchAllQueryBuilder ;
8588import org .opensearch .index .query .MatchNoneQueryBuilder ;
89+ import org .opensearch .index .query .ParsedQuery ;
8690import org .opensearch .index .query .QueryBuilder ;
8791import org .opensearch .index .query .QueryRewriteContext ;
8892import org .opensearch .index .query .QueryShardContext ;
97101import org .opensearch .script .ScriptService ;
98102import org .opensearch .search .aggregations .AggregationInitializationException ;
99103import org .opensearch .search .aggregations .AggregatorFactories ;
104+ import org .opensearch .search .aggregations .AggregatorFactory ;
100105import org .opensearch .search .aggregations .InternalAggregation ;
101106import org .opensearch .search .aggregations .InternalAggregation .ReduceContext ;
102107import org .opensearch .search .aggregations .MultiBucketConsumerService ;
103108import org .opensearch .search .aggregations .SearchContextAggregations ;
104109import org .opensearch .search .aggregations .pipeline .PipelineAggregator .PipelineTree ;
110+ import org .opensearch .search .aggregations .support .ValuesSourceAggregatorFactory ;
105111import org .opensearch .search .builder .SearchSourceBuilder ;
106112import org .opensearch .search .collapse .CollapseContext ;
107113import org .opensearch .search .dfs .DfsPhase ;
162168import static org .opensearch .common .unit .TimeValue .timeValueHours ;
163169import static org .opensearch .common .unit .TimeValue .timeValueMillis ;
164170import static org .opensearch .common .unit .TimeValue .timeValueMinutes ;
171+ import static org .opensearch .search .internal .SearchContext .TRACK_TOTAL_HITS_DISABLED ;
165172
166173/**
167174 * The main search service
@@ -1314,6 +1321,10 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc
13141321 context .evaluateRequestShouldUseConcurrentSearch ();
13151322 return ;
13161323 }
1324+ // Can be marked false for majority cases for which star-tree cannot be used
1325+ // As we increment the cases where star-tree can be used, this can be set back to true
1326+ boolean canUseStarTree = context .mapperService ().isCompositeIndexPresent ();
1327+
13171328 SearchShardTarget shardTarget = context .shardTarget ();
13181329 QueryShardContext queryShardContext = context .getQueryShardContext ();
13191330 context .from (source .from ());
@@ -1324,10 +1335,12 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc
13241335 context .parsedQuery (queryShardContext .toQuery (source .query ()));
13251336 }
13261337 if (source .postFilter () != null ) {
1338+ canUseStarTree = false ;
13271339 InnerHitContextBuilder .extractInnerHits (source .postFilter (), innerHitBuilders );
13281340 context .parsedPostFilter (queryShardContext .toQuery (source .postFilter ()));
13291341 }
1330- if (innerHitBuilders .size () > 0 ) {
1342+ if (!innerHitBuilders .isEmpty ()) {
1343+ canUseStarTree = false ;
13311344 for (Map .Entry <String , InnerHitContextBuilder > entry : innerHitBuilders .entrySet ()) {
13321345 try {
13331346 entry .getValue ().build (context , context .innerHits ());
@@ -1337,11 +1350,10 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc
13371350 }
13381351 }
13391352 if (source .sorts () != null ) {
1353+ canUseStarTree = false ;
13401354 try {
13411355 Optional <SortAndFormats > optionalSort = SortBuilder .buildSort (source .sorts (), context .getQueryShardContext ());
1342- if (optionalSort .isPresent ()) {
1343- context .sort (optionalSort .get ());
1344- }
1356+ optionalSort .ifPresent (context ::sort );
13451357 } catch (IOException e ) {
13461358 throw new SearchException (shardTarget , "failed to create sort elements" , e );
13471359 }
@@ -1355,8 +1367,10 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc
13551367 }
13561368 if (source .trackTotalHitsUpTo () != null ) {
13571369 context .trackTotalHitsUpTo (source .trackTotalHitsUpTo ());
1370+ canUseStarTree = canUseStarTree && (source .trackTotalHitsUpTo () == TRACK_TOTAL_HITS_DISABLED );
13581371 }
13591372 if (source .minScore () != null ) {
1373+ canUseStarTree = false ;
13601374 context .minimumScore (source .minScore ());
13611375 }
13621376 if (source .timeout () != null ) {
@@ -1496,6 +1510,50 @@ private void parseSource(DefaultSearchContext context, SearchSourceBuilder sourc
14961510 if (source .profile ()) {
14971511 context .setProfilers (new Profilers (context .searcher (), context .shouldUseConcurrentSearch ()));
14981512 }
1513+
1514+ if (canUseStarTree ) {
1515+ try {
1516+ setStarTreeQuery (context , queryShardContext , source );
1517+ logger .debug ("can use star tree" );
1518+ } catch (IOException e ) {
1519+ logger .debug ("not using star tree" );
1520+ }
1521+ }
1522+ }
1523+
1524+ private boolean setStarTreeQuery (SearchContext context , QueryShardContext queryShardContext , SearchSourceBuilder source )
1525+ throws IOException {
1526+
1527+ if (source .aggregations () == null ) {
1528+ return false ;
1529+ }
1530+
1531+ // Current implementation assumes only single star-tree is supported
1532+ CompositeDataCubeFieldType compositeMappedFieldType = (StarTreeMapper .StarTreeFieldType ) context .mapperService ()
1533+ .getCompositeFieldTypes ()
1534+ .iterator ()
1535+ .next ();
1536+ CompositeIndexFieldInfo starTree = new CompositeIndexFieldInfo (
1537+ compositeMappedFieldType .name (),
1538+ compositeMappedFieldType .getCompositeIndexType ()
1539+ );
1540+
1541+ ParsedQuery newParsedQuery = queryShardContext .toStarTreeQuery (starTree , compositeMappedFieldType , source .query (), context .query ());
1542+ if (newParsedQuery == null ) {
1543+ return false ;
1544+ }
1545+
1546+ for (AggregatorFactory aggregatorFactory : context .aggregations ().factories ().getFactories ()) {
1547+ if (!(aggregatorFactory instanceof ValuesSourceAggregatorFactory
1548+ && aggregatorFactory .getSubFactories ().getFactories ().length == 0 )) {
1549+ return false ;
1550+ }
1551+ if (queryShardContext .validateStarTreeMetricSuport (compositeMappedFieldType , aggregatorFactory ) == false ) {
1552+ return false ;
1553+ }
1554+ }
1555+ context .parsedQuery (newParsedQuery );
1556+ return true ;
14991557 }
15001558
15011559 /**
@@ -1655,7 +1713,7 @@ public static boolean canMatchSearchAfter(
16551713 && minMax != null
16561714 && primarySortField != null
16571715 && primarySortField .missing () == null
1658- && Objects .equals (trackTotalHitsUpto , SearchContext . TRACK_TOTAL_HITS_DISABLED )) {
1716+ && Objects .equals (trackTotalHitsUpto , TRACK_TOTAL_HITS_DISABLED )) {
16591717 final Object searchAfterPrimary = searchAfter .fields [0 ];
16601718 if (primarySortField .order () == SortOrder .DESC ) {
16611719 if (minMax .compareMin (searchAfterPrimary ) > 0 ) {
0 commit comments