Skip to content

Commit 5072e14

Browse files
committed
ESQL: Fix wildcard for _index field
This is a fairly hacky fix for #129511, a bug where we don't run `LIKE` against the `_index` field in a consistent way. I feel like there should be a better way to fix this, but should work.
1 parent 16d4b91 commit 5072e14

File tree

7 files changed

+122
-4
lines changed

7 files changed

+122
-4
lines changed

server/src/main/java/org/elasticsearch/index/mapper/ConstantFieldType.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.elasticsearch.core.Nullable;
2121
import org.elasticsearch.index.query.QueryRewriteContext;
2222
import org.elasticsearch.index.query.SearchExecutionContext;
23+
import org.elasticsearch.logging.LogManager;
2324

2425
import java.util.Collection;
2526
import java.util.Map;
@@ -128,6 +129,12 @@ public final Query wildcardQuery(
128129
}
129130

130131
public final Query wildcardQuery(String value, boolean caseInsensitive, QueryRewriteContext context) {
132+
LogManager.getLogger(ConstantFieldType.class)
133+
.error(
134+
"ADSFA const eval {} {}",
135+
value,
136+
matches(value, caseInsensitive, context)
137+
);
131138
if (matches(value, caseInsensitive, context)) {
132139
return Queries.newMatchAllQuery();
133140
} else {

server/src/main/java/org/elasticsearch/index/mapper/IndexFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class IndexFieldMapper extends MetadataFieldMapper {
3838

3939
public static final TypeParser PARSER = new FixedTypeParser(c -> INSTANCE);
4040

41-
static final class IndexFieldType extends ConstantFieldType {
41+
public static final class IndexFieldType extends ConstantFieldType {
4242

4343
static final IndexFieldType INSTANCE = new IndexFieldType();
4444

server/src/main/java/org/elasticsearch/index/query/SearchIndexNameMatcher.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
1414
import org.elasticsearch.cluster.service.ClusterService;
1515
import org.elasticsearch.common.regex.Regex;
16+
import org.elasticsearch.index.mapper.ConstantFieldType;
17+
import org.elasticsearch.logging.LogManager;
1618
import org.elasticsearch.transport.RemoteClusterAware;
1719

1820
import java.util.function.Predicate;
@@ -53,7 +55,9 @@ public SearchIndexNameMatcher(
5355
* the separator ':', and must match on both the cluster alias and index name.
5456
*/
5557
public boolean test(String pattern) {
58+
5659
String[] splitIndex = RemoteClusterAware.splitIndexName(pattern);
60+
LogManager.getLogger(ConstantFieldType.class).error("ADSFA {}", (Object) splitIndex);
5761

5862
if (splitIndex[0] == null) {
5963
return clusterAlias == null && matchesIndex(pattern);

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/querydsl/query/WildcardQuery.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,23 @@
66
*/
77
package org.elasticsearch.xpack.esql.core.querydsl.query;
88

9+
import org.apache.lucene.search.MatchAllDocsQuery;
10+
import org.apache.lucene.search.MatchNoDocsQuery;
11+
import org.apache.lucene.search.MultiTermQuery;
12+
import org.elasticsearch.common.regex.Regex;
13+
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
14+
import org.elasticsearch.index.mapper.IndexFieldMapper;
15+
import org.elasticsearch.index.mapper.MappedFieldType;
916
import org.elasticsearch.index.query.QueryBuilder;
17+
import org.elasticsearch.index.query.SearchExecutionContext;
1018
import org.elasticsearch.index.query.WildcardQueryBuilder;
19+
import org.elasticsearch.index.query.support.QueryParsers;
20+
import org.elasticsearch.logging.LogManager;
21+
import org.elasticsearch.logging.Logger;
1122
import org.elasticsearch.xpack.esql.core.tree.Source;
1223

24+
import java.io.IOException;
25+
import java.util.Locale;
1326
import java.util.Objects;
1427

1528
import static org.elasticsearch.index.query.QueryBuilders.wildcardQuery;
@@ -44,9 +57,34 @@ public Boolean caseInsensitive() {
4457

4558
@Override
4659
protected QueryBuilder asBuilder() {
47-
WildcardQueryBuilder wb = wildcardQuery(field, query);
48-
// ES does not allow case_insensitive to be set to "false", it should be either "true" or not specified
49-
return caseInsensitive == false ? wb : wb.caseInsensitive(caseInsensitive);
60+
/*
61+
* Builds WildcardQueryBuilder with simple text matching semantics for
62+
* all fields, including the `_index` field which insists on implementing
63+
* some fairly unexpected matching rules.
64+
*
65+
* Note that
66+
*/
67+
return new WildcardQueryBuilder(field, query) {
68+
@Override
69+
protected org.apache.lucene.search.Query doToQuery(SearchExecutionContext context) throws IOException {
70+
MappedFieldType fieldType = context.getFieldType(fieldName());
71+
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewrite(), null, LoggingDeprecationHandler.INSTANCE);
72+
LogManager.getLogger(WildcardQuery.class).error("ADSFA special query {}", fieldType);
73+
if (fieldType instanceof IndexFieldMapper.IndexFieldType) {
74+
String value = value();
75+
String indexName = context.getFullyQualifiedIndex().getName();
76+
if (WildcardQuery.this.caseInsensitive) {
77+
value = value.toLowerCase(Locale.ROOT);
78+
indexName = indexName.toLowerCase(Locale.ROOT);
79+
}
80+
if (Regex.simpleMatch(value, indexName)) {
81+
return new MatchAllDocsQuery();
82+
}
83+
return new MatchNoDocsQuery();
84+
}
85+
return fieldType.wildcardQuery(value(), method, WildcardQuery.this.caseInsensitive, context);
86+
}
87+
};
5088
}
5189

5290
@Override

x-pack/plugin/esql/qa/server/multi-clusters/src/javaRestTest/java/org/elasticsearch/xpack/esql/ccq/MultiClustersIT.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,64 @@ public void testStats() throws IOException {
371371
assertThat(clusterData, hasKey("took"));
372372
}
373373

374+
public void testLikeIndex() throws Exception {
375+
{
376+
boolean includeCCSMetadata = includeCCSMetadata();
377+
Map<String, Object> result = run("""
378+
FROM test-local-index,*:test-remote-index METADATA _index
379+
| WHERE _index LIKE "*remote*"
380+
| STATS c = COUNT(*) BY _index
381+
| SORT _index ASC
382+
""", includeCCSMetadata);
383+
var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
384+
var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
385+
386+
assertResultMap(includeCCSMetadata, result, columns, values, false);
387+
}
388+
{
389+
boolean includeCCSMetadata = includeCCSMetadata();
390+
Map<String, Object> result = run("""
391+
FROM test-local-index,*:test-remote-index METADATA _index
392+
| WHERE _index NOT LIKE "*remote*"
393+
| STATS c = COUNT(*) BY _index
394+
| SORT _index ASC
395+
""", includeCCSMetadata);
396+
var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
397+
var values = List.of(List.of(localDocs.size(), localIndex));
398+
399+
assertResultMap(includeCCSMetadata, result, columns, values, false);
400+
}
401+
}
402+
403+
public void testRLikeIndex() throws Exception {
404+
{
405+
boolean includeCCSMetadata = includeCCSMetadata();
406+
Map<String, Object> result = run("""
407+
FROM test-local-index,*:test-remote-index METADATA _index
408+
| WHERE _index RLIKE ".*remote.*"
409+
| STATS c = COUNT(*) BY _index
410+
| SORT _index ASC
411+
""", includeCCSMetadata);
412+
var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
413+
var values = List.of(List.of(remoteDocs.size(), REMOTE_CLUSTER_NAME + ":" + remoteIndex));
414+
415+
assertResultMap(includeCCSMetadata, result, columns, values, false);
416+
}
417+
{
418+
boolean includeCCSMetadata = includeCCSMetadata();
419+
Map<String, Object> result = run("""
420+
FROM test-local-index,*:test-remote-index METADATA _index
421+
| WHERE _index NOT RLIKE ".*remote.*"
422+
| STATS c = COUNT(*) BY _index
423+
| SORT _index ASC
424+
""", includeCCSMetadata);
425+
var columns = List.of(Map.of("name", "c", "type", "long"), Map.of("name", "_index", "type", "keyword"));
426+
var values = List.of(List.of(localDocs.size(), localIndex));
427+
428+
assertResultMap(includeCCSMetadata, result, columns, values, false);
429+
}
430+
}
431+
374432
private RestClient remoteClusterClient() throws IOException {
375433
var clusterHosts = parseClusterHosts(remoteCluster.getHttpAddresses());
376434
return buildClient(restClientSettings(), clusterHosts.toArray(new HttpHost[0]));

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/RegexMatch.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.common.io.stream.StreamInput;
1313
import org.elasticsearch.common.io.stream.StreamOutput;
1414
import org.elasticsearch.compute.operator.EvalOperator;
15+
import org.elasticsearch.logging.LogManager;
1516
import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
1617
import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
1718
import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -48,6 +49,7 @@ public Boolean fold(FoldContext ctx) {
4849

4950
@Override
5051
public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
52+
LogManager.getLogger(WildcardLike.class).error("ADSFA toEvaluator");
5153
return AutomataMatch.toEvaluator(
5254
source(),
5355
toEvaluator.apply(field()),

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
1111
import org.elasticsearch.common.io.stream.StreamInput;
1212
import org.elasticsearch.common.io.stream.StreamOutput;
13+
import org.elasticsearch.logging.LogManager;
1314
import org.elasticsearch.xpack.esql.core.expression.Expression;
1415
import org.elasticsearch.xpack.esql.core.expression.FieldAttribute;
1516
import org.elasticsearch.xpack.esql.core.expression.predicate.regex.WildcardPattern;
@@ -108,13 +109,21 @@ protected WildcardLike replaceChild(Expression newLeft) {
108109

109110
@Override
110111
public Translatable translatable(LucenePushdownPredicates pushdownPredicates) {
112+
LogManager.getLogger(WildcardLike.class).error("ADSFA translatable", new Exception());
111113
return pushdownPredicates.isPushableAttribute(field()) ? Translatable.YES : Translatable.NO;
112114
}
113115

114116
@Override
115117
public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
116118
var field = field();
117119
LucenePushdownPredicates.checkIsPushableAttribute(field);
120+
LogManager.getLogger(WildcardLike.class)
121+
.error(
122+
"ADSFA asQuery {} {}",
123+
field,
124+
translateField(handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field)),
125+
new Exception()
126+
);
118127
return translateField(handler.nameOf(field instanceof FieldAttribute fa ? fa.exactAttribute() : field));
119128
}
120129

0 commit comments

Comments
 (0)