Skip to content

Commit 8a58e36

Browse files
authored
Add points metadata support for archive indices (#86655)
Archive indices appear just as regular indices in a cluster, and can be part of index patterns when queried. To allow searches to quickly skip shards of archive indices that might not have relevant data, we're adding support for skipping shards of archive indices here that don't have data falling in the time range being queried. This is critical for the Kibana experience which relies on the date range picker to quickly skip some of the indices in an index pattern. Doing the actual time-range query on the archive index is much more expensive as on a regular index (as it's using doc values instead of points to run the query, equating to a full scan of the columnar data). The solution here is to make points metadata available in archive indices, so that the minimum and maximum value can be retrieved in constant time (only a tiny fraction of the full points capabilities).
1 parent 95c81c8 commit 8a58e36

File tree

11 files changed

+447
-22
lines changed

11 files changed

+447
-22
lines changed

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

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ public DateFieldMapper build(MapperBuilderContext context) {
341341
DateFieldType ft = new DateFieldType(
342342
context.buildFullName(name()),
343343
index.getValue() && indexCreatedVersion.isLegacyIndexVersion() == false,
344+
index.getValue(),
344345
store.getValue(),
345346
docValues.getValue(),
346347
buildFormatter(),
@@ -387,10 +388,12 @@ public static final class DateFieldType extends MappedFieldType {
387388
protected final Resolution resolution;
388389
protected final String nullValue;
389390
protected final FieldValues<Long> scriptValues;
391+
private final boolean pointsMetadataAvailable;
390392

391393
public DateFieldType(
392394
String name,
393395
boolean isIndexed,
396+
boolean pointsMetadataAvailable,
394397
boolean isStored,
395398
boolean hasDocValues,
396399
DateFormatter dateTimeFormatter,
@@ -405,26 +408,52 @@ public DateFieldType(
405408
this.resolution = resolution;
406409
this.nullValue = nullValue;
407410
this.scriptValues = scriptValues;
411+
this.pointsMetadataAvailable = pointsMetadataAvailable;
412+
}
413+
414+
public DateFieldType(
415+
String name,
416+
boolean isIndexed,
417+
boolean isStored,
418+
boolean hasDocValues,
419+
DateFormatter dateTimeFormatter,
420+
Resolution resolution,
421+
String nullValue,
422+
FieldValues<Long> scriptValues,
423+
Map<String, String> meta
424+
) {
425+
this(name, isIndexed, isIndexed, isStored, hasDocValues, dateTimeFormatter, resolution, nullValue, scriptValues, meta);
408426
}
409427

410428
public DateFieldType(String name) {
411-
this(name, true, false, true, DEFAULT_DATE_TIME_FORMATTER, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
429+
this(name, true, true, false, true, DEFAULT_DATE_TIME_FORMATTER, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
412430
}
413431

414432
public DateFieldType(String name, boolean isIndexed) {
415-
this(name, isIndexed, false, true, DEFAULT_DATE_TIME_FORMATTER, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
433+
this(
434+
name,
435+
isIndexed,
436+
isIndexed,
437+
false,
438+
true,
439+
DEFAULT_DATE_TIME_FORMATTER,
440+
Resolution.MILLISECONDS,
441+
null,
442+
null,
443+
Collections.emptyMap()
444+
);
416445
}
417446

418447
public DateFieldType(String name, DateFormatter dateFormatter) {
419-
this(name, true, false, true, dateFormatter, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
448+
this(name, true, true, false, true, dateFormatter, Resolution.MILLISECONDS, null, null, Collections.emptyMap());
420449
}
421450

422451
public DateFieldType(String name, Resolution resolution) {
423-
this(name, true, false, true, DEFAULT_DATE_TIME_FORMATTER, resolution, null, null, Collections.emptyMap());
452+
this(name, true, true, false, true, DEFAULT_DATE_TIME_FORMATTER, resolution, null, null, Collections.emptyMap());
424453
}
425454

426455
public DateFieldType(String name, Resolution resolution, DateFormatter dateFormatter) {
427-
this(name, true, false, true, dateFormatter, resolution, null, null, Collections.emptyMap());
456+
this(name, true, true, false, true, dateFormatter, resolution, null, null, Collections.emptyMap());
428457
}
429458

430459
@Override
@@ -646,7 +675,7 @@ public Relation isFieldWithinQuery(
646675
DateMathParser dateParser,
647676
QueryRewriteContext context
648677
) throws IOException {
649-
if (isIndexed() == false && hasDocValues()) {
678+
if (isIndexed() == false && pointsMetadataAvailable == false && hasDocValues()) {
650679
// we don't have a quick way to run this check on doc values, so fall back to default assuming we are within bounds
651680
return Relation.INTERSECTS;
652681
}

x-pack/plugin/old-lucene-versions/src/internalClusterTest/java/org/elasticsearch/xpack/lucene/bwc/AbstractArchiveTestCase.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
@ESIntegTestCase.ClusterScope(supportsDedicatedMasters = false, numClientNodes = 0, scope = ESIntegTestCase.Scope.TEST)
4242
public abstract class AbstractArchiveTestCase extends AbstractSnapshotIntegTestCase {
4343

44+
@Override
45+
protected boolean addMockInternalEngine() {
46+
return false;
47+
}
48+
4449
@Override
4550
protected Collection<Class<? extends Plugin>> nodePlugins() {
4651
return Arrays.asList(LocalStateOldLuceneVersions.class, TestRepositoryPlugin.class, MockRepository.Plugin.class);

x-pack/plugin/old-lucene-versions/src/main/java/org/elasticsearch/xpack/lucene/bwc/OldLuceneVersions.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,29 @@
2929
import org.elasticsearch.env.Environment;
3030
import org.elasticsearch.env.NodeEnvironment;
3131
import org.elasticsearch.index.IndexModule;
32+
import org.elasticsearch.index.IndexSettings;
3233
import org.elasticsearch.index.engine.Engine;
34+
import org.elasticsearch.index.engine.EngineFactory;
35+
import org.elasticsearch.index.engine.ReadOnlyEngine;
3336
import org.elasticsearch.index.seqno.SequenceNumbers;
3437
import org.elasticsearch.index.shard.IndexEventListener;
3538
import org.elasticsearch.index.shard.IndexShard;
39+
import org.elasticsearch.index.translog.TranslogStats;
3640
import org.elasticsearch.license.License;
3741
import org.elasticsearch.license.LicenseUtils;
3842
import org.elasticsearch.license.LicensedFeature;
3943
import org.elasticsearch.license.XPackLicenseState;
4044
import org.elasticsearch.plugins.ActionPlugin;
4145
import org.elasticsearch.plugins.ClusterPlugin;
46+
import org.elasticsearch.plugins.EnginePlugin;
4247
import org.elasticsearch.plugins.IndexStorePlugin;
4348
import org.elasticsearch.plugins.Plugin;
4449
import org.elasticsearch.plugins.RepositoryPlugin;
4550
import org.elasticsearch.repositories.RepositoriesService;
4651
import org.elasticsearch.script.ScriptService;
4752
import org.elasticsearch.snapshots.Snapshot;
4853
import org.elasticsearch.snapshots.SnapshotRestoreException;
54+
import org.elasticsearch.snapshots.sourceonly.SourceOnlySnapshotRepository;
4955
import org.elasticsearch.threadpool.ThreadPool;
5056
import org.elasticsearch.watcher.ResourceWatcherService;
5157
import org.elasticsearch.xcontent.NamedXContentRegistry;
@@ -60,10 +66,12 @@
6066
import java.util.HashMap;
6167
import java.util.List;
6268
import java.util.Map;
69+
import java.util.Optional;
6370
import java.util.function.BiConsumer;
71+
import java.util.function.Function;
6472
import java.util.function.Supplier;
6573

66-
public class OldLuceneVersions extends Plugin implements IndexStorePlugin, ClusterPlugin, RepositoryPlugin, ActionPlugin {
74+
public class OldLuceneVersions extends Plugin implements IndexStorePlugin, ClusterPlugin, RepositoryPlugin, ActionPlugin, EnginePlugin {
6775

6876
public static final LicensedFeature.Momentary ARCHIVE_FEATURE = LicensedFeature.momentary(
6977
null,
@@ -226,4 +234,17 @@ private static SegmentInfos convertToNewerLuceneVersion(OldSegmentInfos oldSegme
226234
public Map<String, DirectoryFactory> getDirectoryFactories() {
227235
return Map.of();
228236
}
237+
238+
@Override
239+
public Optional<EngineFactory> getEngineFactory(IndexSettings indexSettings) {
240+
if (indexSettings.getIndexVersionCreated().isLegacyIndexVersion()
241+
&& indexSettings.getIndexMetadata().isSearchableSnapshot() == false
242+
&& indexSettings.getValue(SourceOnlySnapshotRepository.SOURCE_ONLY) == false) {
243+
return Optional.of(
244+
engineConfig -> new ReadOnlyEngine(engineConfig, null, new TranslogStats(), true, Function.identity(), true, false)
245+
);
246+
}
247+
248+
return Optional.empty();
249+
}
229250
}

x-pack/plugin/old-lucene-versions/src/main/java/org/elasticsearch/xpack/lucene/bwc/codecs/BWCCodec.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.apache.lucene.codecs.FieldInfosFormat;
1313
import org.apache.lucene.codecs.KnnVectorsFormat;
1414
import org.apache.lucene.codecs.NormsFormat;
15-
import org.apache.lucene.codecs.PointsFormat;
1615
import org.apache.lucene.codecs.SegmentInfoFormat;
1716
import org.apache.lucene.codecs.TermVectorsFormat;
1817
import org.apache.lucene.index.FieldInfo;
@@ -45,11 +44,6 @@ public TermVectorsFormat termVectorsFormat() {
4544
throw new UnsupportedOperationException();
4645
}
4746

48-
@Override
49-
public PointsFormat pointsFormat() {
50-
throw new UnsupportedOperationException();
51-
}
52-
5347
@Override
5448
public KnnVectorsFormat knnVectorsFormat() {
5549
throw new UnsupportedOperationException();
@@ -85,7 +79,7 @@ public void write(Directory directory, SegmentInfo segmentInfo, String segmentSu
8579
};
8680
}
8781

88-
// mark all fields as no term vectors, no norms, no payloads, no points, and no vectors.
82+
// mark all fields as no term vectors, no norms, no payloads, and no vectors.
8983
private static FieldInfos filterFields(FieldInfos fieldInfos) {
9084
List<FieldInfo> fieldInfoCopy = new ArrayList<>(fieldInfos.size());
9185
for (FieldInfo fieldInfo : fieldInfos) {
@@ -100,9 +94,9 @@ private static FieldInfos filterFields(FieldInfos fieldInfos) {
10094
fieldInfo.getDocValuesType(),
10195
fieldInfo.getDocValuesGen(),
10296
fieldInfo.attributes(),
103-
0,
104-
0,
105-
0,
97+
fieldInfo.getPointDimensionCount(),
98+
fieldInfo.getPointIndexDimensionCount(),
99+
fieldInfo.getPointNumBytes(),
106100
0,
107101
fieldInfo.getVectorSimilarityFunction(),
108102
fieldInfo.isSoftDeletesField()

x-pack/plugin/old-lucene-versions/src/main/java/org/elasticsearch/xpack/lucene/bwc/codecs/lucene60/Lucene60Codec.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.lucene.codecs.DocValuesFormat;
2828
import org.apache.lucene.codecs.FieldInfosFormat;
2929
import org.apache.lucene.codecs.LiveDocsFormat;
30+
import org.apache.lucene.codecs.PointsFormat;
3031
import org.apache.lucene.codecs.PostingsFormat;
3132
import org.apache.lucene.codecs.SegmentInfoFormat;
3233
import org.apache.lucene.codecs.StoredFieldsFormat;
@@ -121,4 +122,9 @@ public DocValuesFormat docValuesFormat() {
121122
public PostingsFormat postingsFormat() {
122123
return postingsFormat;
123124
}
125+
126+
@Override
127+
public PointsFormat pointsFormat() {
128+
return new Lucene60MetadataOnlyPointsFormat();
129+
}
124130
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* @notice
3+
* Licensed to the Apache Software Foundation (ASF) under one or more
4+
* contributor license agreements. See the NOTICE file distributed with
5+
* this work for additional information regarding copyright ownership.
6+
* The ASF licenses this file to You under the Apache License, Version 2.0
7+
* (the "License"); you may not use this file except in compliance with
8+
* the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* Modifications copyright (C) 2021 Elasticsearch B.V.
19+
*/
20+
package org.elasticsearch.xpack.lucene.bwc.codecs.lucene60;
21+
22+
import org.apache.lucene.codecs.PointsFormat;
23+
import org.apache.lucene.codecs.PointsReader;
24+
import org.apache.lucene.codecs.PointsWriter;
25+
import org.apache.lucene.index.SegmentReadState;
26+
import org.apache.lucene.index.SegmentWriteState;
27+
28+
import java.io.IOException;
29+
30+
/**
31+
* Allows reading metadata only from Lucene 6.0 point format
32+
**/
33+
public class Lucene60MetadataOnlyPointsFormat extends PointsFormat {
34+
35+
static final String DATA_CODEC_NAME = "Lucene60PointsFormatData";
36+
static final String META_CODEC_NAME = "Lucene60PointsFormatMeta";
37+
38+
/** Filename extension for the leaf blocks */
39+
public static final String DATA_EXTENSION = "dim";
40+
41+
/** Filename extension for the index per field */
42+
public static final String INDEX_EXTENSION = "dii";
43+
44+
static final int DATA_VERSION_START = 0;
45+
static final int DATA_VERSION_CURRENT = DATA_VERSION_START;
46+
47+
static final int INDEX_VERSION_START = 0;
48+
static final int INDEX_VERSION_CURRENT = INDEX_VERSION_START;
49+
50+
/** Sole constructor */
51+
public Lucene60MetadataOnlyPointsFormat() {}
52+
53+
@Override
54+
public PointsWriter fieldsWriter(SegmentWriteState state) {
55+
throw new UnsupportedOperationException("Old codecs may only be used for reading");
56+
}
57+
58+
@Override
59+
public PointsReader fieldsReader(SegmentReadState state) throws IOException {
60+
return new Lucene60MetadataOnlyPointsReader(state);
61+
}
62+
}

0 commit comments

Comments
 (0)