Skip to content

Commit fc32afd

Browse files
Add blockloader to patterned_text to support ESQL (#134093)
The existing blockloader for patterned_text does not work correctly, as it expects BytesRefs which were created by BinaryFieldMapper.CustomBinaryDocValuesField. We need a new simple blockloader reader which directly maps the BytesRefs from a binary doc values to a blockloader reader. This change makes patterned_text work in ESQL.
1 parent 1a1954f commit fc32afd

File tree

5 files changed

+199
-14
lines changed

5 files changed

+199
-14
lines changed

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

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -864,10 +864,10 @@ public String toString() {
864864
}
865865
}
866866

867-
public static class BytesRefsFromBinaryBlockLoader extends DocValuesBlockLoader {
867+
public static class BytesRefsFromCustomBinaryBlockLoader extends DocValuesBlockLoader {
868868
private final String fieldName;
869869

870-
public BytesRefsFromBinaryBlockLoader(String fieldName) {
870+
public BytesRefsFromCustomBinaryBlockLoader(String fieldName) {
871871
this.fieldName = fieldName;
872872
}
873873

@@ -882,16 +882,14 @@ public AllReader reader(LeafReaderContext context) throws IOException {
882882
if (docValues == null) {
883883
return new ConstantNullsReader();
884884
}
885-
return new BytesRefsFromBinary(docValues);
885+
return new BytesRefsFromCustomBinary(docValues);
886886
}
887887
}
888888

889-
private static class BytesRefsFromBinary extends BlockDocValuesReader {
890-
private final BinaryDocValues docValues;
891-
private final ByteArrayStreamInput in = new ByteArrayStreamInput();
892-
private final BytesRef scratch = new BytesRef();
889+
abstract static class AbstractBytesRefsFromBinary extends BlockDocValuesReader {
890+
protected final BinaryDocValues docValues;
893891

894-
BytesRefsFromBinary(BinaryDocValues docValues) {
892+
AbstractBytesRefsFromBinary(BinaryDocValues docValues) {
895893
this.docValues = docValues;
896894
}
897895

@@ -911,7 +909,27 @@ public void read(int docId, BlockLoader.StoredFields storedFields, Builder build
911909
read(docId, (BytesRefBuilder) builder);
912910
}
913911

914-
private void read(int doc, BytesRefBuilder builder) throws IOException {
912+
@Override
913+
public int docId() {
914+
return docValues.docID();
915+
}
916+
917+
abstract void read(int docId, BytesRefBuilder builder) throws IOException;
918+
}
919+
920+
/**
921+
* Read BinaryDocValues encoded by {@link BinaryFieldMapper.CustomBinaryDocValuesField}
922+
*/
923+
static class BytesRefsFromCustomBinary extends AbstractBytesRefsFromBinary {
924+
private final ByteArrayStreamInput in = new ByteArrayStreamInput();
925+
private final BytesRef scratch = new BytesRef();
926+
927+
BytesRefsFromCustomBinary(BinaryDocValues docValues) {
928+
super(docValues);
929+
}
930+
931+
@Override
932+
void read(int doc, BytesRefBuilder builder) throws IOException {
915933
if (false == docValues.advanceExact(doc)) {
916934
builder.appendNull();
917935
return;
@@ -939,8 +957,28 @@ private void read(int doc, BytesRefBuilder builder) throws IOException {
939957
}
940958

941959
@Override
942-
public int docId() {
943-
return docValues.docID();
960+
public String toString() {
961+
return "BlockDocValuesReader.BytesCustom";
962+
}
963+
}
964+
965+
/**
966+
* Read BinaryDocValues with no additional structure in the BytesRefs.
967+
* Each BytesRef from the doc values maps directly to a value in the block loader.
968+
*/
969+
public static class BytesRefsFromBinary extends AbstractBytesRefsFromBinary {
970+
public BytesRefsFromBinary(BinaryDocValues docValues) {
971+
super(docValues);
972+
}
973+
974+
@Override
975+
void read(int doc, BytesRefBuilder builder) throws IOException {
976+
if (false == docValues.advanceExact(doc)) {
977+
builder.appendNull();
978+
return;
979+
}
980+
BytesRef bytes = docValues.binaryValue();
981+
builder.appendBytesRef(bytes);
944982
}
945983

946984
@Override
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.logsdb.patternedtext;
9+
10+
import org.apache.lucene.index.LeafReaderContext;
11+
import org.elasticsearch.index.mapper.BlockDocValuesReader;
12+
13+
import java.io.IOException;
14+
15+
public class PatternedTextBlockLoader extends BlockDocValuesReader.DocValuesBlockLoader {
16+
17+
private final String templateFieldName;
18+
private final String argsFieldName;
19+
private final String argsInfoFieldName;
20+
21+
PatternedTextBlockLoader(String templateFieldName, String argsFieldName, String argsInfoFieldName) {
22+
this.templateFieldName = templateFieldName;
23+
this.argsFieldName = argsFieldName;
24+
this.argsInfoFieldName = argsInfoFieldName;
25+
}
26+
27+
@Override
28+
public BytesRefBuilder builder(BlockFactory factory, int expectedCount) {
29+
return factory.bytesRefs(expectedCount);
30+
}
31+
32+
@Override
33+
public AllReader reader(LeafReaderContext context) throws IOException {
34+
var docValues = PatternedTextDocValues.from(context.reader(), templateFieldName, argsFieldName, argsInfoFieldName);
35+
if (docValues == null) {
36+
return new ConstantNullsReader();
37+
}
38+
return new BlockDocValuesReader.BytesRefsFromBinary(docValues);
39+
}
40+
}

x-pack/plugin/logsdb/src/main/java/org/elasticsearch/xpack/logsdb/patternedtext/PatternedTextFieldType.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.elasticsearch.index.fielddata.FieldDataContext;
3131
import org.elasticsearch.index.fielddata.IndexFieldData;
3232
import org.elasticsearch.index.fielddata.SourceValueFetcherSortedBinaryIndexFieldData;
33-
import org.elasticsearch.index.mapper.BlockDocValuesReader;
3433
import org.elasticsearch.index.mapper.BlockLoader;
3534
import org.elasticsearch.index.mapper.SourceValueFetcher;
3635
import org.elasticsearch.index.mapper.StringFieldType;
@@ -252,7 +251,7 @@ public Query phrasePrefixQuery(TokenStream stream, int slop, int maxExpansions,
252251

253252
@Override
254253
public BlockLoader blockLoader(BlockLoaderContext blContext) {
255-
return new BlockDocValuesReader.BytesRefsFromBinaryBlockLoader(name());
254+
return new PatternedTextBlockLoader(templateFieldName(), argsFieldName(), argsInfoFieldName());
256255
}
257256

258257
@Override
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
setup:
3+
- requires:
4+
cluster_features: [ "mapper.patterned_text" ]
5+
reason: "patterned_text mappings are used in this test"
6+
7+
- do:
8+
indices.create:
9+
index: test
10+
body:
11+
settings:
12+
index:
13+
mapping.source.mode: synthetic
14+
mappings:
15+
properties:
16+
"@timestamp":
17+
type: date
18+
message:
19+
type: patterned_text
20+
# defaults to index_options: docs
21+
22+
- do:
23+
bulk:
24+
index: test
25+
refresh: true
26+
body:
27+
- { "index": { "_id": "1" } }
28+
- { "@timestamp": "2025-07-17T00:00:01Z" }
29+
- { "index": { "_id": "2" } }
30+
- { "message": "Found 5 errors for service [cheddar1]", "@timestamp": "2025-07-17T00:00:02Z" }
31+
# template_id: mOVsnxlxdac
32+
- { "index": { "_id": "3" } }
33+
- { "message": "[2020-08-18T00:58:56] Found 123 errors for service [cheddar1]", "@timestamp": "2025-07-17T00:00:03Z" }
34+
# template_id: 1l_PtCLQ5xY
35+
- { "index": { "_id": "4" } }
36+
- { "message": "Found some errors for cheddar data service", "@timestamp": "2025-07-17T00:00:04Z"}
37+
# template_id: k-2qtjujOCw
38+
- { "index": { "_id": "5" } }
39+
- { "message": "Found 123 errors for service [gorgonzola-24]", "@timestamp": "2025-07-17T00:00:05Z" }
40+
# template_id: mOVsnxlxdac
41+
42+
---
43+
teardown:
44+
- do:
45+
indices.delete:
46+
index: test
47+
48+
---
49+
"Simple from":
50+
- do:
51+
esql.query:
52+
body:
53+
query: 'FROM test | SORT @timestamp | KEEP message, message.template_id | LIMIT 10'
54+
55+
- match: {columns.0.name: "message"}
56+
- match: {columns.0.type: "text"}
57+
- match: {columns.1.name: "message.template_id"}
58+
- match: {columns.1.type: "keyword"}
59+
60+
- length: {values: 5}
61+
- match: {values.0.0: null }
62+
- match: {values.0.1: null }
63+
- match: {values.1.0: "Found 5 errors for service [cheddar1]" }
64+
- match: {values.1.1: "mOVsnxlxdac" }
65+
- match: {values.2.0: "[2020-08-18T00:58:56] Found 123 errors for service [cheddar1]" }
66+
- match: {values.2.1: "1l_PtCLQ5xY" }
67+
- match: {values.3.0: "Found some errors for cheddar data service" }
68+
- match: {values.3.1: "k-2qtjujOCw" }
69+
- match: {values.4.0: "Found 123 errors for service [gorgonzola-24]" }
70+
- match: {values.4.1: "mOVsnxlxdac" }
71+
72+
---
73+
"match query":
74+
- do:
75+
esql.query:
76+
body:
77+
query: 'FROM test | WHERE MATCH(message, "gorgonzola-24") | KEEP message | LIMIT 10'
78+
79+
- length: {values: 1}
80+
- match: {values.0.0: "Found 123 errors for service [gorgonzola-24]" }
81+
82+
---
83+
"match phrase query":
84+
- do:
85+
esql.query:
86+
body:
87+
query: 'FROM test | WHERE MATCH_PHRASE(message, "123 errors") | SORT @timestamp | KEEP message | LIMIT 10'
88+
89+
- length: {values: 2}
90+
- match: {values.0.0: "[2020-08-18T00:58:56] Found 123 errors for service [cheddar1]" }
91+
- match: {values.1.0: "Found 123 errors for service [gorgonzola-24]" }
92+
93+
---
94+
"template_id stats":
95+
- do:
96+
esql.query:
97+
body:
98+
query: 'FROM test | STATS count(*) BY message.template_id | SORT message.template_id | LIMIT 10'
99+
100+
- length: {values: 4}
101+
- match: {values.0.0: 1 }
102+
- match: {values.0.1: "1l_PtCLQ5xY" }
103+
- match: {values.1.0: 1 }
104+
- match: {values.1.1: "k-2qtjujOCw" }
105+
- match: {values.2.0: 2 }
106+
- match: {values.2.1: "mOVsnxlxdac" }
107+
- match: {values.3.0: 1 }
108+
- match: {values.3.1: null }

x-pack/plugin/wildcard/src/main/java/org/elasticsearch/xpack/wildcard/mapper/WildcardFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ public Query prefixQuery(
956956
@Override
957957
public BlockLoader blockLoader(BlockLoaderContext blContext) {
958958
if (hasDocValues()) {
959-
return new BlockDocValuesReader.BytesRefsFromBinaryBlockLoader(name());
959+
return new BlockDocValuesReader.BytesRefsFromCustomBinaryBlockLoader(name());
960960
}
961961
return null;
962962
}

0 commit comments

Comments
 (0)