Skip to content

ESQL: Add documents_found and values_loaded (#125631) #130029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/125631.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 125631
summary: Add `documents_found` and `values_loaded`
area: ES|QL
type: enhancement
issues: []
2 changes: 2 additions & 0 deletions docs/reference/esql/esql-rest.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ Which returns:
{
"took": 28,
"is_partial": false,
"documents_found": 5,
"values_loaded": 20,
"columns": [
{"name": "author", "type": "text"},
{"name": "name", "type": "text"},
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/esql/functions/description/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions docs/reference/esql/functions/examples/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions docs/reference/esql/functions/functionNamedParams/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions docs/reference/esql/functions/layout/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions docs/reference/esql/functions/parameters/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/reference/esql/functions/signature/knn.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions docs/reference/esql/functions/types/knn.asciidoc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion docs/reference/esql/multivalued-fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Multivalued fields come back as a JSON array:
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 5,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "long"}
Expand Down Expand Up @@ -80,6 +82,8 @@ And {esql} sees that removal:
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 5,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "keyword"}
Expand Down Expand Up @@ -125,6 +129,8 @@ And {esql} also sees that:
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 7,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "long"}
Expand Down Expand Up @@ -169,6 +175,8 @@ POST /_query
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 7,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "keyword"}
Expand Down Expand Up @@ -203,6 +211,8 @@ POST /_query
{
"took": 28,
"is_partial": false,
"documents_found": 1,
"values_loaded": 2,
"columns": [
{ "name": "a", "type": "long"},
],
Expand Down Expand Up @@ -247,6 +257,8 @@ POST /_query
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 5,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "long"},
Expand All @@ -271,7 +283,7 @@ Work around this limitation by converting the field to single value with one of:
* <<esql-mv_min>>
* <<esql-mv_sum>>

[source,console,esql-multivalued-fields-mv-into-null]
[source,console,esql-multivalued-fields-mv-min]
----
POST /_query
{
Expand All @@ -285,6 +297,8 @@ POST /_query
{
"took": 28,
"is_partial": false,
"documents_found": 2,
"values_loaded": 5,
"columns": [
{ "name": "a", "type": "long"},
{ "name": "b", "type": "long"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ static TransportVersion def(int id) {
public static final TransportVersion SPARSE_VECTOR_FIELD_PRUNING_OPTIONS_8_19 = def(8_841_0_58);
public static final TransportVersion ML_INFERENCE_ELASTIC_DENSE_TEXT_EMBEDDINGS_ADDED_8_19 = def(8_841_0_59);
public static final TransportVersion ML_INFERENCE_COHERE_API_VERSION_8_19 = def(8_841_0_60);
public static final TransportVersion ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19 = def(8_841_0_61);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/org/elasticsearch/common/Strings.java
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ public static String toString(ChunkedToXContent chunkedToXContent, boolean prett
* Allows to configure the params.
* Allows to control whether the outputted json needs to be pretty printed and human readable.
*/
private static String toString(ToXContent toXContent, ToXContent.Params params, boolean pretty, boolean human) {
public static String toString(ToXContent toXContent, ToXContent.Params params, boolean pretty, boolean human) {
try {
XContentBuilder builder = createBuilder(pretty, human);
if (toXContent.isFragment()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2704,8 +2704,13 @@ protected static MapMatcher getProfileMatcher() {
.entry("drivers", instanceOf(List.class));
}

protected static MapMatcher getResultMatcher(boolean includeMetadata, boolean includePartial) {
protected static MapMatcher getResultMatcher(boolean includeMetadata, boolean includePartial, boolean includeDocumentsFound) {
MapMatcher mapMatcher = matchesMap();
if (includeDocumentsFound) {
// Older versions may not return documents_found and values_loaded.
mapMatcher = mapMatcher.entry("documents_found", greaterThanOrEqualTo(0));
mapMatcher = mapMatcher.entry("values_loaded", greaterThanOrEqualTo(0));
}
if (includeMetadata) {
mapMatcher = mapMatcher.entry("took", greaterThanOrEqualTo(0));
}
Expand All @@ -2720,7 +2725,7 @@ protected static MapMatcher getResultMatcher(boolean includeMetadata, boolean in
* Create empty result matcher from result, taking into account all metadata items.
*/
protected static MapMatcher getResultMatcher(Map<String, Object> result) {
return getResultMatcher(result.containsKey("took"), result.containsKey("is_partial"));
return getResultMatcher(result.containsKey("took"), result.containsKey("is_partial"), result.containsKey("documents_found"));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ public int getPositionCount() {

@Override
public int getTotalValueCount() {
throw new UnsupportedOperationException("Composite block");
int totalValueCount = 0;
for (Block b : blocks) {
totalValueCount += b.getTotalValueCount();
}
return totalValueCount;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ public Map<String, LuceneSliceQueue.PartitioningStrategy> partitioningStrategies
return partitioningStrategies;
}

@Override
public long documentsFound() {
return rowsEmitted;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import java.util.function.IntFunction;
import java.util.function.Supplier;

import static org.elasticsearch.TransportVersions.ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19;

/**
* Operator that extracts doc_values from a Lucene index out of pages that have been produced by {@link LuceneSourceOperator}
* and outputs them to a new column.
Expand Down Expand Up @@ -112,6 +114,7 @@ public record ShardContext(IndexReader reader, Supplier<SourceLoader> newSourceL
private final BlockFactory blockFactory;

private final Map<String, Integer> readersBuilt = new TreeMap<>();
private long valuesLoaded;

int lastShard = -1;
int lastSegment = -1;
Expand Down Expand Up @@ -158,6 +161,9 @@ public int get(int i) {
}
}
success = true;
for (Block b : blocks) {
valuesLoaded += b.getTotalValueCount();
}
return page.appendBlocks(blocks);
} catch (IOException e) {
throw new UncheckedIOException(e);
Expand Down Expand Up @@ -548,7 +554,7 @@ public String toString() {

@Override
protected Status status(long processNanos, int pagesProcessed, long rowsReceived, long rowsEmitted) {
return new Status(new TreeMap<>(readersBuilt), processNanos, pagesProcessed, rowsReceived, rowsEmitted);
return new Status(new TreeMap<>(readersBuilt), processNanos, pagesProcessed, rowsReceived, rowsEmitted, valuesLoaded);
}

/**
Expand Down Expand Up @@ -593,21 +599,34 @@ public static class Status extends AbstractPageMappingOperator.Status {
);

private final Map<String, Integer> readersBuilt;

Status(Map<String, Integer> readersBuilt, long processNanos, int pagesProcessed, long rowsReceived, long rowsEmitted) {
private final long valuesLoaded;

Status(
Map<String, Integer> readersBuilt,
long processNanos,
int pagesProcessed,
long rowsReceived,
long rowsEmitted,
long valuesLoaded
) {
super(processNanos, pagesProcessed, rowsReceived, rowsEmitted);
this.readersBuilt = readersBuilt;
this.valuesLoaded = valuesLoaded;
}

Status(StreamInput in) throws IOException {
super(in);
readersBuilt = in.readOrderedMap(StreamInput::readString, StreamInput::readVInt);
valuesLoaded = in.getTransportVersion().onOrAfter(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19) ? in.readVLong() : 0;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeMap(readersBuilt, StreamOutput::writeVInt);
if (out.getTransportVersion().onOrAfter(ESQL_DOCUMENTS_FOUND_AND_VALUES_LOADED_8_19)) {
out.writeVLong(valuesLoaded);
}
}

@Override
Expand All @@ -619,6 +638,11 @@ public Map<String, Integer> readersBuilt() {
return readersBuilt;
}

@Override
public long valuesLoaded() {
return valuesLoaded;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
Expand All @@ -627,6 +651,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.field(e.getKey(), e.getValue());
}
builder.endObject();
builder.field("values_loaded", valuesLoaded);
innerToXContent(builder);
return builder.endObject();
}
Expand All @@ -635,12 +660,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
public boolean equals(Object o) {
if (super.equals(o) == false) return false;
Status status = (Status) o;
return readersBuilt.equals(status.readersBuilt);
return readersBuilt.equals(status.readersBuilt) && valuesLoaded == status.valuesLoaded;
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), readersBuilt);
return Objects.hash(super.hashCode(), readersBuilt, valuesLoaded);
}

@Override
Expand Down Expand Up @@ -750,6 +775,4 @@ public BlockLoader.AggregateMetricDoubleBuilder aggregateMetricDoubleBuilder(int
return factory.newAggregateMetricDoubleBlockBuilder(count);
}
}

// TODO tests that mix source loaded fields and doc values in the same block
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public class Driver implements Releasable, Describable {
private final DriverContext driverContext;
private final Supplier<String> description;
private final List<Operator> activeOperators;
private final List<DriverStatus.OperatorStatus> statusOfCompletedOperators = new ArrayList<>();
private final List<OperatorStatus> statusOfCompletedOperators = new ArrayList<>();
private final Releasable releasable;
private final long statusNanos;

Expand Down Expand Up @@ -343,7 +343,7 @@ private void closeEarlyFinishedOperators() {
Iterator<Operator> itr = finishedOperators.iterator();
while (itr.hasNext()) {
Operator op = itr.next();
statusOfCompletedOperators.add(new DriverStatus.OperatorStatus(op.toString(), op.status()));
statusOfCompletedOperators.add(new OperatorStatus(op.toString(), op.status()));
op.close();
itr.remove();
}
Expand Down Expand Up @@ -570,7 +570,7 @@ private void updateStatus(long extraCpuNanos, int extraIterations, DriverStatus.
prev.iterations() + extraIterations,
status,
statusOfCompletedOperators,
activeOperators.stream().map(op -> new DriverStatus.OperatorStatus(op.toString(), op.status())).toList(),
activeOperators.stream().map(op -> new OperatorStatus(op.toString(), op.status())).toList(),
sleeps
);
});
Expand Down
Loading