-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Simplify index pattern #134215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify index pattern #134215
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,31 +15,15 @@ | |
import org.elasticsearch.xpack.esql.plan.logical.UnresolvedRelation; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import static java.util.Collections.emptyList; | ||
|
||
/** | ||
* This class is part of the planner. Acts somewhat like a linker, to find the indices and enrich policies referenced by the query. | ||
*/ | ||
public class PreAnalyzer { | ||
|
||
public static class PreAnalysis { | ||
public static final PreAnalysis EMPTY = new PreAnalysis(null, emptyList(), emptyList(), emptyList()); | ||
|
||
public final IndexMode indexMode; | ||
public final List<IndexPattern> indices; | ||
public final List<Enrich> enriches; | ||
public final List<IndexPattern> lookupIndices; | ||
|
||
public PreAnalysis(IndexMode indexMode, List<IndexPattern> indices, List<Enrich> enriches, List<IndexPattern> lookupIndices) { | ||
this.indexMode = indexMode; | ||
this.indices = indices; | ||
this.enriches = enriches; | ||
this.lookupIndices = lookupIndices; | ||
} | ||
public record PreAnalysis(IndexMode indexMode, IndexPattern index, List<Enrich> enriches, List<IndexPattern> lookupIndices) { | ||
public static final PreAnalysis EMPTY = new PreAnalysis(null, null, List.of(), List.of()); | ||
} | ||
|
||
public PreAnalysis preAnalyze(LogicalPlan plan) { | ||
|
@@ -51,18 +35,19 @@ public PreAnalysis preAnalyze(LogicalPlan plan) { | |
} | ||
|
||
protected PreAnalysis doPreAnalyze(LogicalPlan plan) { | ||
Set<IndexPattern> indices = new HashSet<>(); | ||
|
||
Holder<IndexMode> indexMode = new Holder<>(); | ||
Holder<IndexPattern> index = new Holder<>(); | ||
|
||
List<Enrich> unresolvedEnriches = new ArrayList<>(); | ||
List<IndexPattern> lookupIndices = new ArrayList<>(); | ||
|
||
Holder<IndexMode> indexMode = new Holder<>(); | ||
plan.forEachUp(UnresolvedRelation.class, p -> { | ||
if (p.indexMode() == IndexMode.LOOKUP) { | ||
lookupIndices.add(p.indexPattern()); | ||
} else if (indexMode.get() == null || indexMode.get() == p.indexMode()) { | ||
indexMode.set(p.indexMode()); | ||
indices.add(p.indexPattern()); | ||
index.set(p.indexPattern()); | ||
} else { | ||
throw new IllegalStateException("index mode is already set"); | ||
} | ||
|
@@ -73,7 +58,6 @@ protected PreAnalysis doPreAnalyze(LogicalPlan plan) { | |
// mark plan as preAnalyzed (if it were marked, there would be no analysis) | ||
plan.forEachUp(LogicalPlan::setPreAnalyzed); | ||
|
||
return new PreAnalysis(indexMode.get(), indices.stream().toList(), unresolvedEnriches, lookupIndices); | ||
return new PreAnalysis(indexMode.get(), index.get(), unresolvedEnriches, lookupIndices); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -322,20 +322,19 @@ static void updateExecutionInfoAtEndOfPlanning(EsqlExecutionInfo execInfo) { | |
public static void initCrossClusterState( | ||
IndicesExpressionGrouper indicesGrouper, | ||
XPackLicenseState licenseState, | ||
List<IndexPattern> patterns, | ||
IndexPattern index, | ||
|
||
EsqlExecutionInfo executionInfo | ||
) throws ElasticsearchStatusException { | ||
if (patterns.isEmpty()) { | ||
if (index == null) { | ||
return; | ||
} | ||
assert patterns.size() == 1 : "Only single index pattern is supported"; | ||
try { | ||
var groupedIndices = indicesGrouper.groupIndices( | ||
// indicesGrouper.getConfiguredClusters() might return mutable set that changes as clusters connect or disconnect. | ||
// it is copied here so that we have the same resolution when request contains multiple remote cluster patterns with * | ||
Set.copyOf(indicesGrouper.getConfiguredClusters()), | ||
IndicesOptions.DEFAULT, | ||
patterns.getFirst().indexPattern() | ||
index.indexPattern() | ||
); | ||
|
||
executionInfo.clusterInfoInitializing(true); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,6 @@ | |
import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry; | ||
import org.elasticsearch.xpack.esql.index.EsIndex; | ||
import org.elasticsearch.xpack.esql.index.IndexResolution; | ||
import org.elasticsearch.xpack.esql.index.MappingException; | ||
import org.elasticsearch.xpack.esql.inference.InferenceResolution; | ||
import org.elasticsearch.xpack.esql.inference.InferenceService; | ||
import org.elasticsearch.xpack.esql.optimizer.LogicalPlanOptimizer; | ||
|
@@ -374,14 +373,14 @@ public void analyzedPlan( | |
} | ||
|
||
var preAnalysis = preAnalyzer.preAnalyze(parsed); | ||
EsqlCCSUtils.initCrossClusterState(indicesExpressionGrouper, verifier.licenseState(), preAnalysis.indices, executionInfo); | ||
EsqlCCSUtils.initCrossClusterState(indicesExpressionGrouper, verifier.licenseState(), preAnalysis.index(), executionInfo); | ||
|
||
SubscribableListener. // | ||
<EnrichResolution>newForked(l -> enrichPolicyResolver.resolvePolicies(preAnalysis.enriches, executionInfo, l)) | ||
<EnrichResolution>newForked(l -> enrichPolicyResolver.resolvePolicies(preAnalysis.enriches(), executionInfo, l)) | ||
.<PreAnalysisResult>andThenApply(enrichResolution -> FieldNameUtils.resolveFieldNames(parsed, enrichResolution)) | ||
.<PreAnalysisResult>andThen((l, r) -> resolveInferences(parsed, r, l)) | ||
.<PreAnalysisResult>andThen((l, r) -> preAnalyzeMainIndices(preAnalysis, executionInfo, r, requestFilter, l)) | ||
.<PreAnalysisResult>andThen((l, r) -> preAnalyzeLookupIndices(preAnalysis.lookupIndices.iterator(), r, executionInfo, l)) | ||
.<PreAnalysisResult>andThen((l, r) -> preAnalyzeLookupIndices(preAnalysis.lookupIndices().iterator(), r, executionInfo, l)) | ||
.<LogicalPlan>andThen((l, r) -> analyzeWithRetry(parsed, requestFilter, preAnalysis, executionInfo, r, l)) | ||
.addListener(logicalPlanListener); | ||
} | ||
|
@@ -633,26 +632,20 @@ private void preAnalyzeMainIndices( | |
ThreadPool.Names.SEARCH_COORDINATION, | ||
ThreadPool.Names.SYSTEM_READ | ||
); | ||
// TODO we plan to support joins in the future when possible, but for now we'll just fail early if we see one | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already support lookup joins and they require a separate data structure. |
||
List<IndexPattern> indices = preAnalysis.indices; | ||
if (indices.size() > 1) { | ||
// Note: JOINs are not supported but we detect them when | ||
listener.onFailure(new MappingException("Queries with multiple indices are not supported")); | ||
} else if (indices.size() == 1) { | ||
IndexPattern table = indices.getFirst(); | ||
|
||
// if the preceding call to the enrich policy API found unavailable clusters, recreate the index expression to search | ||
// based only on available clusters (which could now be an empty list) | ||
if (preAnalysis.index() == null) { | ||
// occurs when dealing with local relations (row a = 1) | ||
listener.onResponse(result.withIndexResolution(IndexResolution.invalid("[none specified]"))); | ||
} else { | ||
String indexExpressionToResolve = EsqlCCSUtils.createIndexExpressionFromAvailableClusters(executionInfo); | ||
if (indexExpressionToResolve.isEmpty()) { | ||
// if this was a pure remote CCS request (no local indices) and all remotes are offline, return an empty IndexResolution | ||
listener.onResponse( | ||
result.withIndexResolution(IndexResolution.valid(new EsIndex(table.indexPattern(), Map.of(), Map.of()))) | ||
result.withIndexResolution(IndexResolution.valid(new EsIndex(preAnalysis.index().indexPattern(), Map.of(), Map.of()))) | ||
); | ||
} else { | ||
boolean includeAllDimensions = false; | ||
// call the EsqlResolveFieldsAction (field-caps) to resolve indices and get field types | ||
if (preAnalysis.indexMode == IndexMode.TIME_SERIES) { | ||
if (preAnalysis.indexMode() == IndexMode.TIME_SERIES) { | ||
includeAllDimensions = true; | ||
// TODO: Maybe if no indices are returned, retry without index mode and provide a clearer error message. | ||
var indexModeFilter = new TermQueryBuilder(IndexModeFieldMapper.NAME, IndexMode.TIME_SERIES.getName()); | ||
|
@@ -672,13 +665,6 @@ private void preAnalyzeMainIndices( | |
}) | ||
); | ||
} | ||
} else { | ||
try { | ||
// occurs when dealing with local relations (row a = 1) | ||
listener.onResponse(result.withIndexResolution(IndexResolution.invalid("[none specified]"))); | ||
} catch (Exception ex) { | ||
listener.onFailure(ex); | ||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover: In case that we somehow find 2 indices in the same mode, we're going to silently throw away the previous one.
There shouldn't be 2 indices. This is enforced in
EsqlSession#preAnalyzeMainIndices
.