Skip to content

Commit 14a33df

Browse files
committed
Merge remote-tracking branch 'origin/tsdb/use-large-numeric-blocks' into tsdb/use-large-numeric-blocks
2 parents 6337db1 + 90d0f43 commit 14a33df

File tree

39 files changed

+223
-70
lines changed

39 files changed

+223
-70
lines changed

docs/changelog/138559.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 138559
2+
summary: Accept `project_routing` as query parameter
3+
area: EQL
4+
type: enhancement
5+
issues: []

docs/changelog/138568.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 138568
2+
summary: Use doc values skipper for `_tsid` in synthetic `_id` postings
3+
area: TSDB
4+
type: enhancement
5+
issues: []

docs/changelog/138718.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 138718
2+
summary: Add `project_routing` option
3+
area: SQL
4+
type: enhancement
5+
issues: []

server/src/main/java/org/elasticsearch/index/codec/tsdb/TSDBSyntheticIdFieldsProducer.java

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -280,22 +280,44 @@ private BytesRef lookupTsIdOrd(int tsIdOrdinal) throws IOException {
280280
}
281281

282282
/**
283-
* Scan all documents to find the first document that has a _tsid equal or greater than the provided _tsid ordinal, returning its
284-
* document ID. If no document is found, the method returns {@link DocIdSetIterator#NO_MORE_DOCS}.
283+
* Use a doc values skipper to find a starting document ID for the provided _tsid ordinal. The returned document ID might have the
284+
* exact _tsid ordinal provided, or a lower one.
285285
*
286-
* Warning: This method is very slow because it potentially scans all documents in the segment.
286+
* @param tsIdOrd the _tsid ordinal
287+
* @return a docID to start scanning documents from in order to find the first document ID matching the provided _tsid
288+
* @throws IOException if any I/O exception occurs
287289
*/
288-
private int slowScanToFirstDocWithTsIdOrdinalEqualOrGreaterThan(int tsIdOrd) throws IOException {
290+
private int findStartDocIDForTsIdOrd(int tsIdOrd) throws IOException {
291+
var skipper = docValuesProducer.getSkipper(tsIdFieldInfo);
292+
assert skipper != null;
293+
if (skipper.minValue() > tsIdOrd || tsIdOrd > skipper.maxValue()) {
294+
return DocIdSetIterator.NO_MORE_DOCS;
295+
}
296+
skipper.advance(tsIdOrd, Long.MAX_VALUE);
297+
return skipper.minDocID(0);
298+
}
299+
300+
/**
301+
* Find the first document that has a _tsid equal or greater than the provided _tsid ordinal, returning its document ID. If no
302+
* document is found, the method returns {@link DocIdSetIterator#NO_MORE_DOCS}.
303+
*
304+
* Warning: This method can be slow because it potentially scans many documents in the segment.
305+
*/
306+
private int findFirstDocWithTsIdOrdinalEqualOrGreaterThan(int tsIdOrd) throws IOException {
307+
final int startDocId = findStartDocIDForTsIdOrd(tsIdOrd);
308+
if (startDocId == DocIdSetIterator.NO_MORE_DOCS) {
309+
return startDocId;
310+
}
289311
// recreate even if doc values are already on the same ordinal, to ensure the method returns the first doc
290-
if (tsIdDocValues == null || (cachedTsIdOrd != -1 && cachedTsIdOrd >= tsIdOrd)) {
312+
if (tsIdDocValues == null || (cachedTsIdOrd != -1 && cachedTsIdOrd >= tsIdOrd) || tsIdDocValues.docID() > startDocId) {
291313
tsIdDocValues = docValuesProducer.getSorted(tsIdFieldInfo);
292314
cachedTsIdOrd = -1;
293315
cachedTsId = null;
294316
}
295317
assert 0 <= tsIdOrd : tsIdOrd;
296318
assert tsIdOrd < tsIdDocValues.getValueCount() : tsIdOrd;
297319

298-
for (int docID = 0; docID != DocIdSetIterator.NO_MORE_DOCS; docID = tsIdDocValues.nextDoc()) {
320+
for (int docID = startDocId; docID != DocIdSetIterator.NO_MORE_DOCS; docID = tsIdDocValues.nextDoc()) {
299321
boolean found = tsIdDocValues.advanceExact(docID);
300322
assert found : "No value found for field [" + tsIdFieldInfo.getName() + " and docID " + docID;
301323
var ord = tsIdDocValues.ordValue();
@@ -313,22 +335,25 @@ private int slowScanToFirstDocWithTsIdOrdinalEqualOrGreaterThan(int tsIdOrd) thr
313335
}
314336

315337
/**
316-
* Scan all documents to find the first document that has a _tsid equal to the provided _tsid ordinal, returning its
317-
* document ID. If no document is found, the method returns {@link DocIdSetIterator#NO_MORE_DOCS}.
338+
* Find the first document that has a _tsid equal to the provided _tsid ordinal, returning its document ID. If no document is found,
339+
* the method returns {@link DocIdSetIterator#NO_MORE_DOCS}.
318340
*
319-
* Warning: This method is very slow because it potentially scans all documents in the segment.
341+
* Warning: This method can be slow because it potentially scans many documents in the segment.
320342
*/
321-
private int slowScanToFirstDocWithTsIdOrdinalEqualTo(int tsIdOrd) throws IOException {
343+
private int findFirstDocWithTsIdOrdinalEqualTo(int tsIdOrd) throws IOException {
344+
final int startDocId = findStartDocIDForTsIdOrd(tsIdOrd);
345+
assert startDocId != DocIdSetIterator.NO_MORE_DOCS : startDocId;
346+
322347
// recreate even if doc values are already on the same ordinal, to ensure the method returns the first doc
323-
if (tsIdDocValues == null || (cachedTsIdOrd != -1 && cachedTsIdOrd >= tsIdOrd)) {
348+
if (tsIdDocValues == null || (cachedTsIdOrd != -1 && cachedTsIdOrd >= tsIdOrd) || tsIdDocValues.docID() > startDocId) {
324349
tsIdDocValues = docValuesProducer.getSorted(tsIdFieldInfo);
325350
cachedTsIdOrd = -1;
326351
cachedTsId = null;
327352
}
328353
assert 0 <= tsIdOrd : tsIdOrd;
329354
assert tsIdOrd < tsIdDocValues.getValueCount() : tsIdOrd;
330355

331-
for (int docID = 0; docID != DocIdSetIterator.NO_MORE_DOCS; docID = tsIdDocValues.nextDoc()) {
356+
for (int docID = startDocId; docID != DocIdSetIterator.NO_MORE_DOCS; docID = tsIdDocValues.nextDoc()) {
332357
boolean found = tsIdDocValues.advanceExact(docID);
333358
assert found : "No value found for field [" + tsIdFieldInfo.getName() + " and docID " + docID;
334359
var ord = tsIdDocValues.ordValue();
@@ -441,7 +466,7 @@ public SeekStatus seekCeil(BytesRef id) throws IOException {
441466
tsIdOrd = -tsIdOrd - 1;
442467
// set the terms enum on the first non-matching document
443468
if (tsIdOrd < docValues.getTsIdValueCount()) {
444-
int docID = docValues.slowScanToFirstDocWithTsIdOrdinalEqualOrGreaterThan(tsIdOrd);
469+
int docID = docValues.findFirstDocWithTsIdOrdinalEqualOrGreaterThan(tsIdOrd);
445470
if (docID != DocIdSetIterator.NO_MORE_DOCS) {
446471
current = new SyntheticTerm(
447472
docID,
@@ -461,8 +486,8 @@ public SeekStatus seekCeil(BytesRef id) throws IOException {
461486
// _tsid found, extract the timestamp
462487
final long timestamp = TsidExtractingIdFieldMapper.extractTimestampFromSyntheticId(id);
463488

464-
// Slow scan to the first document matching the _tsid
465-
final int startDocID = docValues.slowScanToFirstDocWithTsIdOrdinalEqualTo(tsIdOrd);
489+
// Find the first document matching the _tsid
490+
final int startDocID = docValues.findFirstDocWithTsIdOrdinalEqualTo(tsIdOrd);
466491
assert startDocID >= 0 : startDocID;
467492

468493
int docID = startDocID;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public static ParsedDocument noopTombstone(SeqNoFieldMapper.SeqNoIndexOptions se
7575
* The returned document consists only _uid, _seqno, _term and _version fields; other metadata fields are excluded.
7676
* @param id the id of the deleted document
7777
*/
78+
// used by tests
7879
public static ParsedDocument deleteTombstone(SeqNoFieldMapper.SeqNoIndexOptions seqNoIndexOptions, String id) {
7980
return deleteTombstone(seqNoIndexOptions, false /* ignored */, false, id, null /* ignored */);
8081
}
@@ -101,6 +102,9 @@ public static ParsedDocument deleteTombstone(
101102
// Use a synthetic _id field which is not indexed nor stored
102103
document.add(IdFieldMapper.syntheticIdField(id));
103104

105+
// Add doc values fields that are used to synthesize the synthetic _id.
106+
// Note: It is not strictly required for tombstones documents but we decided to add them so that iterating and seeking synthetic
107+
// _id terms over tombstones also work as if a regular _id field was present.
104108
var timeSeriesId = TsidExtractingIdFieldMapper.extractTimeSeriesIdFromSyntheticId(uid);
105109
var timestamp = TsidExtractingIdFieldMapper.extractTimestampFromSyntheticId(uid);
106110
var routingHash = TsidExtractingIdFieldMapper.extractRoutingHashBytesFromSyntheticId(uid);

x-pack/plugin/eql/qa/common/src/main/java/org/elasticsearch/test/eql/EqlRestTestCase.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ public void checkSearchContent() throws Exception {
6161
""", validQuery), "query malformed, empty clause found" },
6262
{ String.format(Locale.ROOT, """
6363
{"query": "%s", "max_samples_per_key": 0}
64-
""", validQuery), "max_samples_per_key must be greater than 0" } };
64+
""", validQuery), "max_samples_per_key must be greater than 0" },
65+
{ String.format(Locale.ROOT, """
66+
{"query": "%s", "project_routing": "foo"}
67+
""", validQuery), "[project_routing] is only allowed when cross-project search is enabled" } };
6568

6669
public void testBadRequests() throws Exception {
6770
createIndex(defaultValidationIndexName, (String) null);

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/action/EqlSearchRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public class EqlSearchRequest extends LegacyActionRequest implements IndicesRequ
9090
static final String KEY_MAX_SAMPLES_PER_KEY = "max_samples_per_key";
9191
static final String KEY_ALLOW_PARTIAL_SEARCH_RESULTS = "allow_partial_search_results";
9292
static final String KEY_ALLOW_PARTIAL_SEQUENCE_RESULTS = "allow_partial_sequence_results";
93+
static final String KEY_PROJECT_ROUTING = "project_routing";
9394

9495
static final ParseField FILTER = new ParseField(KEY_FILTER);
9596
static final ParseField TIMESTAMP_FIELD = new ParseField(KEY_TIMESTAMP_FIELD);
@@ -106,6 +107,7 @@ public class EqlSearchRequest extends LegacyActionRequest implements IndicesRequ
106107
static final ParseField MAX_SAMPLES_PER_KEY = new ParseField(KEY_MAX_SAMPLES_PER_KEY);
107108
static final ParseField ALLOW_PARTIAL_SEARCH_RESULTS = new ParseField(KEY_ALLOW_PARTIAL_SEARCH_RESULTS);
108109
static final ParseField ALLOW_PARTIAL_SEQUENCE_RESULTS = new ParseField(KEY_ALLOW_PARTIAL_SEQUENCE_RESULTS);
110+
static final ParseField PROJECT_ROUTING = new ParseField(KEY_PROJECT_ROUTING);
109111

110112
private static final ObjectParser<EqlSearchRequest, Void> PARSER = objectParser(EqlSearchRequest::new);
111113

@@ -301,6 +303,7 @@ protected static <R extends EqlSearchRequest> ObjectParser<R, Void> objectParser
301303
parser.declareInt(EqlSearchRequest::maxSamplesPerKey, MAX_SAMPLES_PER_KEY);
302304
parser.declareBoolean(EqlSearchRequest::allowPartialSearchResults, ALLOW_PARTIAL_SEARCH_RESULTS);
303305
parser.declareBoolean(EqlSearchRequest::allowPartialSequenceResults, ALLOW_PARTIAL_SEQUENCE_RESULTS);
306+
parser.declareString(EqlSearchRequest::projectRouting, PROJECT_ROUTING);
304307
return parser;
305308
}
306309

x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/plugin/RestEqlSearchAction.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.xpack.eql.action.EqlSearchAction;
3030
import org.elasticsearch.xpack.eql.action.EqlSearchRequest;
3131
import org.elasticsearch.xpack.eql.action.EqlSearchResponse;
32+
import org.elasticsearch.xpack.ql.InvalidArgumentException;
3233

3334
import java.io.IOException;
3435
import java.util.List;
@@ -87,6 +88,10 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
8788
eqlRequest.allowPartialSequenceResults(
8889
request.paramAsBoolean("allow_partial_sequence_results", eqlRequest.allowPartialSequenceResults())
8990
);
91+
eqlRequest.projectRouting(request.param("project_routing", eqlRequest.getProjectRouting()));
92+
if (crossProjectEnabled == false && eqlRequest.getProjectRouting() != null) {
93+
throw new InvalidArgumentException("[project_routing] is only allowed when cross-project search is enabled");
94+
}
9095
}
9196

9297
return channel -> {

x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/action/EqlRequestParserTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public void testSearchRequestParser() throws IOException {
6868
"timestamp_field": "tsf",
6969
"event_category_field": "etf",
7070
"size": "101",
71+
"project_routing": "_alias:_origin",
7172
"query": "file where user != 'SYSTEM' by file_path"
7273
}""", EqlSearchRequest::fromXContent);
7374
assertArrayEquals(new String[] { "endgame-*" }, request.indices());
@@ -81,6 +82,7 @@ public void testSearchRequestParser() throws IOException {
8182
assertEquals(101, request.size());
8283
assertEquals(1000, request.fetchSize());
8384
assertEquals("file where user != 'SYSTEM' by file_path", request.query());
85+
assertEquals("_alias:_origin", request.getProjectRouting());
8486
}
8587

8688
private EqlSearchRequest generateRequest(String index, String json, Function<XContentParser, EqlSearchRequest> fromXContent)

x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/action/EqlSearchRequestTests.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ protected EqlSearchRequest createTestInstance() {
8181
.keepOnCompletion(randomBoolean())
8282
.allowPartialSearchResults(randomBoolean())
8383
.allowPartialSequenceResults(randomBoolean())
84+
.projectRouting(randomAlphaOfLength(10))
8485
.fetchFields(randomFetchFields)
8586
.runtimeMappings(randomRuntimeMappings())
8687
.resultPosition(randomFrom("tail", "head"))
@@ -143,6 +144,7 @@ protected EqlSearchRequest mutateInstanceForVersion(EqlSearchRequest instance, T
143144
mutatedInstance.allowPartialSequenceResults(
144145
version.supports(TransportVersions.V_8_18_0) ? instance.allowPartialSequenceResults() : false
145146
);
147+
mutatedInstance.projectRouting(instance.getProjectRouting());
146148

147149
return mutatedInstance;
148150
}

0 commit comments

Comments
 (0)