Skip to content

Commit c18497e

Browse files
Adds usage stats for vectors
_xpack/usage "vectors": { "available": true, "enabled": true, "dense_vector_fields_count" : 1, "sparse_vector_fields_count" : 1, "dense_vector_dims_avg_count" : 100 } Backport for elastic#44512
1 parent e4b7ae2 commit c18497e

File tree

4 files changed

+194
-3
lines changed

4 files changed

+194
-3
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/vectors/VectorsFeatureSetUsage.java

+55-1
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,72 @@
77
package org.elasticsearch.xpack.core.vectors;
88

99
import org.elasticsearch.common.io.stream.StreamInput;
10+
import org.elasticsearch.common.io.stream.StreamOutput;
11+
import org.elasticsearch.common.xcontent.XContentBuilder;
1012
import org.elasticsearch.xpack.core.XPackFeatureSet;
1113
import org.elasticsearch.xpack.core.XPackField;
1214

1315
import java.io.IOException;
16+
import java.util.Objects;
1417

1518
public class VectorsFeatureSetUsage extends XPackFeatureSet.Usage {
1619

20+
private final int numDenseVectorFields;
21+
private final int numSparseVectorFields;
22+
private final int avgDenseVectorDims;
23+
1724
public VectorsFeatureSetUsage(StreamInput input) throws IOException {
1825
super(input);
26+
numDenseVectorFields = input.readVInt();
27+
numSparseVectorFields = input.readVInt();
28+
avgDenseVectorDims = input.readVInt();
29+
}
30+
31+
@Override
32+
public void writeTo(StreamOutput out) throws IOException {
33+
super.writeTo(out);
34+
out.writeVInt(numDenseVectorFields);
35+
out.writeVInt(numSparseVectorFields);
36+
out.writeVInt(avgDenseVectorDims);
1937
}
2038

21-
public VectorsFeatureSetUsage(boolean available, boolean enabled) {
39+
public VectorsFeatureSetUsage(boolean available, boolean enabled, int numDenseVectorFields, int numSparseVectorFields,
40+
int avgDenseVectorDims) {
2241
super(XPackField.VECTORS, available, enabled);
42+
this.numDenseVectorFields = numDenseVectorFields;
43+
this.numSparseVectorFields = numSparseVectorFields;
44+
this.avgDenseVectorDims = avgDenseVectorDims;
45+
}
46+
47+
48+
@Override
49+
protected void innerXContent(XContentBuilder builder, Params params) throws IOException {
50+
super.innerXContent(builder, params);
51+
builder.field("dense_vector_fields_count", numDenseVectorFields);
52+
builder.field("sparse_vector_fields_count", numSparseVectorFields);
53+
builder.field("dense_vector_dims_avg_count", avgDenseVectorDims);
54+
}
55+
56+
public int numDenseVectorFields() {
57+
return numDenseVectorFields;
58+
}
59+
public int numSparseVectorFields() {
60+
return numSparseVectorFields;
61+
}
62+
public int avgDenseVectorDims() {
63+
return avgDenseVectorDims;
64+
}
65+
66+
@Override
67+
public int hashCode() {
68+
return Objects.hash(available, enabled, numDenseVectorFields, numSparseVectorFields, avgDenseVectorDims);
69+
}
70+
71+
@Override
72+
public boolean equals(Object obj) {
73+
if (obj instanceof VectorsFeatureSetUsage == false) return false;
74+
VectorsFeatureSetUsage other = (VectorsFeatureSetUsage) obj;
75+
return available == other.available && enabled == other.enabled && numDenseVectorFields == other.numDenseVectorFields
76+
&& numSparseVectorFields == other.numSparseVectorFields && avgDenseVectorDims == other.avgDenseVectorDims;
2377
}
2478
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.core.vectors;
7+
8+
import org.elasticsearch.common.io.stream.Writeable;
9+
import org.elasticsearch.test.AbstractWireSerializingTestCase;
10+
11+
import java.io.IOException;
12+
13+
public class VectorsFeatureSetUsageTests extends AbstractWireSerializingTestCase<VectorsFeatureSetUsage> {
14+
15+
@Override
16+
protected VectorsFeatureSetUsage createTestInstance() {
17+
boolean available = randomBoolean();
18+
boolean enabled = randomBoolean();
19+
if (available && enabled) {
20+
return new VectorsFeatureSetUsage(available, enabled, randomIntBetween(0, 100000), randomIntBetween(0, 100000),
21+
randomIntBetween(0, 1024));
22+
} else {
23+
return new VectorsFeatureSetUsage(available, enabled, 0, 0, 0);
24+
}
25+
}
26+
27+
@Override
28+
protected VectorsFeatureSetUsage mutateInstance(VectorsFeatureSetUsage instance) throws IOException {
29+
boolean available = instance.available();
30+
boolean enabled = instance.enabled();
31+
int numDenseVectorFields = instance.numDenseVectorFields();
32+
int numSparseVectorFields = instance.numSparseVectorFields();
33+
int avgDenseVectorDims = instance.avgDenseVectorDims();
34+
35+
if (available == false || enabled == false) {
36+
available = true;
37+
enabled = true;
38+
}
39+
numDenseVectorFields = randomValueOtherThan(numDenseVectorFields, () -> randomIntBetween(0, 100000));
40+
numSparseVectorFields = randomValueOtherThan(numSparseVectorFields, () -> randomIntBetween(0, 100000));
41+
avgDenseVectorDims = randomValueOtherThan(avgDenseVectorDims, () -> randomIntBetween(0, 1024));
42+
return new VectorsFeatureSetUsage(available, enabled, numDenseVectorFields, numSparseVectorFields, avgDenseVectorDims);
43+
}
44+
45+
@Override
46+
protected Writeable.Reader<VectorsFeatureSetUsage> instanceReader() {
47+
return VectorsFeatureSetUsage::new;
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
setup:
2+
- skip:
3+
features: headers
4+
version: " - 7.3.99"
5+
reason: "vector stats was added from 7.4"
6+
7+
---
8+
"Usage stats on vector fields":
9+
- do: {xpack.usage: {}}
10+
- match: { vectors.available: true }
11+
- match: { vectors.enabled: true }
12+
- match: { vectors.dense_vector_fields_count: 0 }
13+
- match: { vectors.sparse_vector_fields_count: 0 }
14+
- match: { vectors.dense_vector_dims_avg_count: 0 }
15+
16+
- do:
17+
indices.create:
18+
index: test-index1
19+
body:
20+
mappings:
21+
properties:
22+
my_dense_vector1:
23+
type: dense_vector
24+
dims: 10
25+
my_dense_vector2:
26+
type: dense_vector
27+
dims: 30
28+
29+
- do:
30+
indices.create:
31+
index: test-index2
32+
body:
33+
mappings:
34+
properties:
35+
my_dense_vector3:
36+
type: dense_vector
37+
dims: 20
38+
my_sparse_vector1:
39+
type: sparse_vector
40+
41+
- do: {xpack.usage: {}}
42+
- match: { vectors.available: true }
43+
- match: { vectors.enabled: true }
44+
- match: { vectors.dense_vector_fields_count: 3 }
45+
- match: { vectors.sparse_vector_fields_count: 1 }
46+
- match: { vectors.dense_vector_dims_avg_count: 20 }

x-pack/plugin/vectors/src/main/java/org/elasticsearch/xpack/vectors/VectorsFeatureSet.java

+43-2
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,32 @@
66
package org.elasticsearch.xpack.vectors;
77

88
import org.elasticsearch.action.ActionListener;
9+
import org.elasticsearch.cluster.metadata.IndexMetaData;
10+
import org.elasticsearch.cluster.metadata.MappingMetaData;
11+
import org.elasticsearch.cluster.service.ClusterService;
912
import org.elasticsearch.common.inject.Inject;
1013
import org.elasticsearch.common.settings.Settings;
1114
import org.elasticsearch.license.XPackLicenseState;
1215
import org.elasticsearch.xpack.core.XPackFeatureSet;
1316
import org.elasticsearch.xpack.core.XPackField;
1417
import org.elasticsearch.xpack.core.XPackSettings;
1518
import org.elasticsearch.xpack.core.vectors.VectorsFeatureSetUsage;
19+
import org.elasticsearch.xpack.vectors.mapper.DenseVectorFieldMapper;
20+
import org.elasticsearch.xpack.vectors.mapper.SparseVectorFieldMapper;
1621

1722
import java.util.Map;
1823

1924
public class VectorsFeatureSet implements XPackFeatureSet {
2025

2126
private final boolean enabled;
2227
private final XPackLicenseState licenseState;
28+
private final ClusterService clusterService;
2329

2430
@Inject
25-
public VectorsFeatureSet(Settings settings, XPackLicenseState licenseState) {
31+
public VectorsFeatureSet(Settings settings, XPackLicenseState licenseState, ClusterService clusterService) {
2632
this.enabled = XPackSettings.VECTORS_ENABLED.get(settings);
2733
this.licenseState = licenseState;
34+
this.clusterService = clusterService;
2835
}
2936

3037
@Override
@@ -49,6 +56,40 @@ public Map<String, Object> nativeCodeInfo() {
4956

5057
@Override
5158
public void usage(ActionListener<XPackFeatureSet.Usage> listener) {
52-
listener.onResponse(new VectorsFeatureSetUsage(available(), enabled()));
59+
boolean vectorsAvailable = available();
60+
boolean vectorsEnabled = enabled();
61+
int numDenseVectorFields = 0;
62+
int numSparseVectorFields = 0;
63+
int avgDenseVectorDims = 0;
64+
65+
if (vectorsAvailable && vectorsEnabled && clusterService.state() != null) {
66+
for (IndexMetaData indexMetaData : clusterService.state().metaData()) {
67+
MappingMetaData mappingMetaData = indexMetaData.mapping();
68+
if (mappingMetaData != null) {
69+
Map<String, Object> mappings = mappingMetaData.getSourceAsMap();
70+
if (mappings.containsKey("properties")) {
71+
@SuppressWarnings("unchecked") Map<String, Map<String, Object>> fieldMappings =
72+
(Map<String, Map<String, Object>>) mappings.get("properties");
73+
for (Map<String, Object> typeDefinition : fieldMappings.values()) {
74+
String fieldType = (String) typeDefinition.get("type");
75+
if (fieldType != null) {
76+
if (fieldType.equals(DenseVectorFieldMapper.CONTENT_TYPE)) {
77+
numDenseVectorFields++;
78+
int dims = (Integer) typeDefinition.get("dims");
79+
avgDenseVectorDims += dims;
80+
} else if (fieldType.equals(SparseVectorFieldMapper.CONTENT_TYPE)) {
81+
numSparseVectorFields++;
82+
}
83+
}
84+
}
85+
}
86+
}
87+
}
88+
if (numDenseVectorFields > 0) {
89+
avgDenseVectorDims = avgDenseVectorDims / numDenseVectorFields;
90+
}
91+
}
92+
listener.onResponse(new VectorsFeatureSetUsage(vectorsAvailable, vectorsEnabled,
93+
numDenseVectorFields, numSparseVectorFields, avgDenseVectorDims));
5394
}
5495
}

0 commit comments

Comments
 (0)