Skip to content

Commit

Permalink
Add to SearchUsages queries generated by the vector tiles API
Browse files Browse the repository at this point in the history
  • Loading branch information
iverase committed Sep 24, 2024
1 parent 11d968d commit 15b11de
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
import org.elasticsearch.geometry.Polygon;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.geometry.utils.WellKnownText;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.geogrid.GeoTileUtils;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.ObjectPath;
import org.hamcrest.Matchers;
import org.junit.AfterClass;
import org.junit.Before;
Expand Down Expand Up @@ -790,7 +793,9 @@ public void testBasicQueryGet() throws Exception {
}
}
}""");
final int termsUsage = queryUsage(TermQueryBuilder.NAME);
final VectorTile.Tile tile = execute(mvtRequest);
assertThat(queryUsage(TermQueryBuilder.NAME), Matchers.equalTo(termsUsage + 1));
assertThat(tile.getLayersCount(), Matchers.equalTo(3));
assertLayer(tile, HITS_LAYER, 4096, 1, 2);
assertLayer(tile, AGGS_LAYER, 4096, 1, 2);
Expand Down Expand Up @@ -1060,12 +1065,21 @@ private void assertBucketKeyTag(VectorTile.Tile.Layer layer, VectorTile.Tile.Fea
}

private VectorTile.Tile execute(Request mvtRequest) throws IOException {
final int geoShapeUsage = queryUsage(GeoShapeQueryBuilder.NAME);
final Response response = client().performRequest(mvtRequest);
assertThat(queryUsage(GeoShapeQueryBuilder.NAME), Matchers.equalTo(geoShapeUsage + 1));
final InputStream inputStream = response.getEntity().getContent();
assertThat(response.getStatusLine().getStatusCode(), Matchers.equalTo(HttpStatus.SC_OK));
return VectorTile.Tile.parseFrom(inputStream);
}

private int queryUsage(String queryName) throws IOException {
final Request request = new Request(HttpGet.METHOD_NAME, "/_cluster/stats?filter_path=indices.search.queries." + queryName);
ObjectPath objectPath = ObjectPath.createFromResponse(client().performRequest(request));
Integer count = objectPath.evaluate("indices.search.queries." + queryName);
return count == null ? 0 : count;
}

private VectorTile.Tile.Layer getLayer(VectorTile.Tile tile, String layerName) {
for (int i = 0; i < tile.getLayersCount(); i++) {
final VectorTile.Tile.Layer layer = tile.getLayers(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ public List<RestHandler> getRestHandlers(
Supplier<DiscoveryNodes> nodesInCluster,
Predicate<NodeFeature> clusterSupportsFeature
) {
return List.of(new RestVectorTileAction());
return List.of(new RestVectorTileAction(restController.getSearchUsageHolder()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.elasticsearch.search.fetch.subphase.FieldAndFormat;
import org.elasticsearch.search.profile.SearchProfileResults;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.usage.SearchUsageHolder;
import org.elasticsearch.xpack.vectortile.feature.FeatureFactory;

import java.io.IOException;
Expand Down Expand Up @@ -87,7 +88,11 @@ public class RestVectorTileAction extends BaseRestHandler {
// internal label position runtime field name
static final String LABEL_POSITION_FIELD_NAME = INTERNAL_AGG_PREFIX + "label_position";

public RestVectorTileAction() {}
private final SearchUsageHolder searchUsageHolder;

public RestVectorTileAction(SearchUsageHolder searchUsageHolder) {
this.searchUsageHolder = searchUsageHolder;
}

@Override
public List<Route> routes() {
Expand All @@ -103,7 +108,7 @@ public String getName() {
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
// This will allow to cancel the search request if the http channel is closed
final RestCancellableNodeClient cancellableNodeClient = new RestCancellableNodeClient(client, restRequest.getHttpChannel());
final VectorTileRequest request = VectorTileRequest.parseRestRequest(restRequest);
final VectorTileRequest request = VectorTileRequest.parseRestRequest(restRequest, searchUsageHolder);
final SearchRequestBuilder searchRequestBuilder = searchRequestBuilder(cancellableNodeClient, request);
return channel -> searchRequestBuilder.execute(new RestResponseListener<>(channel) {

Expand Down Expand Up @@ -207,6 +212,7 @@ private static SearchRequestBuilder searchRequestBuilder(RestCancellableNodeClie
searchRequestBuilder.setRuntimeMappings(runtimeMappings);
// For Hex aggregation we might need to buffer the bounding box
final Rectangle boxFilter = request.getGridAgg().bufferTile(request.getBoundingBox(), request.getZ(), request.getGridPrecision());

QueryBuilder qBuilder = QueryBuilders.geoShapeQuery(request.getField(), boxFilter);
if (request.getQueryBuilder() != null) {
final BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.elasticsearch.core.Booleans;
import org.elasticsearch.geometry.Rectangle;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.script.Script;
Expand All @@ -25,6 +26,8 @@
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.usage.SearchUsage;
import org.elasticsearch.usage.SearchUsageHolder;
import org.elasticsearch.xcontent.ObjectParser;
import org.elasticsearch.xcontent.ParseField;
import org.elasticsearch.xcontent.XContentParser;
Expand Down Expand Up @@ -75,7 +78,7 @@ protected static class Defaults {
public static final int TRACK_TOTAL_HITS_UP_TO = DEFAULT_TRACK_TOTAL_HITS_UP_TO;
}

private static final ObjectParser<VectorTileRequest, RestRequest> PARSER;
private static final ObjectParser<VectorTileRequest, SearchUsage> PARSER;

static {
PARSER = new ObjectParser<>("vector-tile");
Expand All @@ -89,7 +92,7 @@ protected static class Defaults {
}, SearchSourceBuilder.FETCH_FIELDS_FIELD, ObjectParser.ValueType.OBJECT_ARRAY);
PARSER.declareField(
VectorTileRequest::setQueryBuilder,
(p, c) -> AbstractQueryBuilder.parseTopLevelQuery(p),
(p, c) -> AbstractQueryBuilder.parseTopLevelQuery(p, c::trackQueryUsage),
SearchSourceBuilder.QUERY_FIELD,
ObjectParser.ValueType.OBJECT
);
Expand Down Expand Up @@ -130,19 +133,23 @@ protected static class Defaults {
}, SearchSourceBuilder.TRACK_TOTAL_HITS_FIELD, ObjectParser.ValueType.VALUE);
}

static VectorTileRequest parseRestRequest(RestRequest restRequest) throws IOException {
static VectorTileRequest parseRestRequest(RestRequest restRequest, SearchUsageHolder searchUsageHolder) throws IOException {
final VectorTileRequest request = new VectorTileRequest(
Strings.splitStringByCommaToArray(restRequest.param(INDEX_PARAM)),
restRequest.param(FIELD_PARAM),
Integer.parseInt(restRequest.param(Z_PARAM)),
Integer.parseInt(restRequest.param(X_PARAM)),
Integer.parseInt(restRequest.param(Y_PARAM))
);
final SearchUsage searchUsage = new SearchUsage();
if (restRequest.hasContentOrSourceParam()) {
try (XContentParser contentParser = restRequest.contentOrSourceParamParser()) {
PARSER.parse(contentParser, request, restRequest);
PARSER.parse(contentParser, request, searchUsage);
}
}
// The API generates a query on the fly that we track here.
searchUsage.trackQueryUsage(GeoShapeQueryBuilder.NAME);
searchUsageHolder.updateUsage(searchUsage);
// Following the same strategy of the _search API, some parameters can be defined in the body or as URL parameters.
// URL parameters takes precedence so we check them here.
if (restRequest.hasParam(SearchSourceBuilder.SIZE_FIELD.getPreferredName())) {
Expand Down

0 comments on commit 15b11de

Please sign in to comment.