Skip to content

Commit 0d59c1d

Browse files
committed
Add IgnoredSourceFieldLoader
1 parent 609ee45 commit 0d59c1d

File tree

3 files changed

+151
-9
lines changed

3 files changed

+151
-9
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.index.fieldvisitor;
11+
12+
import org.apache.lucene.index.FieldInfo;
13+
import org.apache.lucene.index.LeafReaderContext;
14+
import org.apache.lucene.index.StoredFieldVisitor;
15+
import org.apache.lucene.util.BytesRef;
16+
import org.elasticsearch.common.bytes.BytesReference;
17+
import org.elasticsearch.index.mapper.BlockLoader;
18+
import org.elasticsearch.index.mapper.IgnoredSourceFieldMapper;
19+
20+
import java.io.IOException;
21+
import java.util.ArrayList;
22+
import java.util.HashMap;
23+
import java.util.HashSet;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Set;
27+
28+
class IgnoredSourceFieldLoader extends StoredFieldLoader {
29+
private final boolean forceSequentialReader;
30+
private final Map<String, Set<String>> potentialFieldsInIgnoreSource;
31+
private final Set<String> fieldNames;
32+
33+
IgnoredSourceFieldLoader(BlockLoader.FieldsSpec spec, boolean forceSequentialReader) {
34+
fieldNames = new HashSet<>(spec.ignoredFieldsSpec().requiredIgnoredFields());
35+
this.forceSequentialReader = forceSequentialReader;
36+
37+
HashMap<String, Set<String>> potentialFieldsInIgnoreSource = new HashMap<>();
38+
for (String requiredIgnoredField : spec.ignoredFieldsSpec().requiredIgnoredFields()) {
39+
for (String potentialStoredField : spec.ignoredFieldsSpec().format().requiredStoredFields(requiredIgnoredField)) {
40+
potentialFieldsInIgnoreSource.computeIfAbsent(potentialStoredField, k -> new HashSet<>()).add(requiredIgnoredField);
41+
}
42+
}
43+
this.potentialFieldsInIgnoreSource = potentialFieldsInIgnoreSource;
44+
}
45+
46+
@Override
47+
public LeafStoredFieldLoader getLoader(LeafReaderContext ctx, int[] docs) throws IOException {
48+
var reader = forceSequentialReader ? sequentialReader(ctx) : reader(ctx, docs);
49+
var visitor = new SFV(fieldNames, potentialFieldsInIgnoreSource);
50+
return new LeafStoredFieldLoader() {
51+
52+
private int doc = -1;
53+
54+
@Override
55+
public void advanceTo(int doc) throws IOException {
56+
if (doc != this.doc) {
57+
visitor.reset();
58+
reader.accept(doc, visitor);
59+
this.doc = doc;
60+
}
61+
}
62+
63+
@Override
64+
public BytesReference source() {
65+
assert false : "source() is not supported by IgnoredSourceFieldLoader";
66+
return null;
67+
}
68+
69+
@Override
70+
public String id() {
71+
assert false : "id() is not supported by IgnoredSourceFieldLoader";
72+
return null;
73+
}
74+
75+
@Override
76+
public String routing() {
77+
assert false : "routing() is not supported by IgnoredSourceFieldLoader";
78+
return null;
79+
}
80+
81+
@Override
82+
public Map<String, List<Object>> storedFields() {
83+
return visitor.values;
84+
}
85+
};
86+
}
87+
88+
@Override
89+
public List<String> fieldsToLoad() {
90+
return potentialFieldsInIgnoreSource.keySet().stream().toList();
91+
}
92+
93+
static class SFV extends StoredFieldVisitor {
94+
final Map<String, List<Object>> values = new HashMap<>();
95+
final Set<String> fieldNames;
96+
private final Set<String> unvisitedFields;
97+
final Map<String, Set<String>> potentialFieldsInIgnoreSource;
98+
99+
SFV(Set<String> fieldNames, Map<String, Set<String>> potentialFieldsInIgnoreSource) {
100+
this.fieldNames = fieldNames;
101+
this.unvisitedFields = new HashSet<>(fieldNames);
102+
this.potentialFieldsInIgnoreSource = potentialFieldsInIgnoreSource;
103+
}
104+
105+
@Override
106+
public Status needsField(FieldInfo fieldInfo) throws IOException {
107+
if (unvisitedFields.isEmpty()) {
108+
return Status.STOP;
109+
}
110+
111+
Set<String> foundFields = potentialFieldsInIgnoreSource.get(fieldInfo.name);
112+
if (foundFields == null) {
113+
return Status.NO;
114+
}
115+
116+
unvisitedFields.removeAll(foundFields);
117+
return Status.YES;
118+
}
119+
120+
@Override
121+
public void binaryField(FieldInfo fieldInfo, byte[] value) {
122+
values.computeIfAbsent(fieldInfo.name, k -> new ArrayList<>()).add(new BytesRef(value));
123+
}
124+
125+
void reset() {
126+
values.clear();
127+
unvisitedFields.addAll(fieldNames);
128+
}
129+
130+
}
131+
132+
static boolean supports(BlockLoader.FieldsSpec spec) {
133+
return spec.storedFieldsSpec().noRequirements()
134+
&& spec.ignoredFieldsSpec().format() == IgnoredSourceFieldMapper.IgnoredSourceFormat.PER_FIELD_IGNORED_SOURCE;
135+
}
136+
}

server/src/main/java/org/elasticsearch/index/fieldvisitor/StoredFieldLoader.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.apache.lucene.index.FieldInfo;
1313
import org.apache.lucene.index.LeafReader;
1414
import org.apache.lucene.index.LeafReaderContext;
15+
import org.apache.lucene.index.StoredFieldVisitor;
1516
import org.apache.lucene.index.StoredFields;
1617
import org.elasticsearch.common.CheckedBiConsumer;
1718
import org.elasticsearch.common.bytes.BytesReference;
@@ -64,10 +65,9 @@ public static StoredFieldLoader fromSpec(BlockLoader.FieldsSpec spec, boolean fo
6465
return StoredFieldLoader.empty();
6566
}
6667

67-
// TODO
68-
// if (IgnoredSourceFieldLoader.supports(spec)) {
69-
// return new IgnoredSourceFieldLoader(spec);
70-
// }
68+
if (IgnoredSourceFieldLoader.supports(spec)) {
69+
return new IgnoredSourceFieldLoader(spec, forceSequentialReader);
70+
}
7171

7272
StoredFieldsSpec mergedSpec = spec.storedFieldsSpec().merge(spec.ignoredFieldsSpec().requiredStoredFields());
7373
if (forceSequentialReader) {
@@ -163,7 +163,8 @@ public List<String> fieldsToLoad() {
163163
};
164164
}
165165

166-
private static CheckedBiConsumer<Integer, FieldsVisitor, IOException> reader(LeafReaderContext ctx, int[] docs) throws IOException {
166+
protected static CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> reader(LeafReaderContext ctx, int[] docs)
167+
throws IOException {
167168
LeafReader leafReader = ctx.reader();
168169
if (docs != null && docs.length > 10 && hasSequentialDocs(docs)) {
169170
return sequentialReader(ctx);
@@ -172,7 +173,8 @@ private static CheckedBiConsumer<Integer, FieldsVisitor, IOException> reader(Lea
172173
return storedFields::document;
173174
}
174175

175-
private static CheckedBiConsumer<Integer, FieldsVisitor, IOException> sequentialReader(LeafReaderContext ctx) throws IOException {
176+
protected static CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> sequentialReader(LeafReaderContext ctx)
177+
throws IOException {
176178
LeafReader leafReader = ctx.reader();
177179
if (leafReader instanceof SequentialStoredFieldsLeafReader lf) {
178180
return lf.getSequentialStoredFieldsReader()::document;
@@ -223,7 +225,7 @@ public Map<String, List<Object>> storedFields() {
223225

224226
private static class ReaderStoredFieldLoader implements LeafStoredFieldLoader {
225227

226-
private final CheckedBiConsumer<Integer, FieldsVisitor, IOException> reader;
228+
private final CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> reader;
227229
private final CustomFieldsVisitor visitor;
228230
private int doc = -1;
229231

@@ -243,7 +245,11 @@ public Status needsField(FieldInfo fieldInfo) {
243245
return new CustomFieldsVisitor(fields, loadSource);
244246
}
245247

246-
ReaderStoredFieldLoader(CheckedBiConsumer<Integer, FieldsVisitor, IOException> reader, boolean loadSource, Set<String> fields) {
248+
ReaderStoredFieldLoader(
249+
CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> reader,
250+
boolean loadSource,
251+
Set<String> fields
252+
) {
247253
this.reader = reader;
248254
this.visitor = getFieldsVisitor(fields, loadSource);
249255
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ static BytesRef encodeMultipleValuesForField(List<NameValue> values) {
200200
}
201201
}
202202

203-
static List<NameValue> decodeMultipleValuesForField(BytesRef value) {
203+
public static List<NameValue> decodeMultipleValuesForField(BytesRef value) {
204204
try {
205205
StreamInput stream = new BytesArray(value).streamInput();
206206
var count = stream.readVInt();

0 commit comments

Comments
 (0)