Skip to content

Commit 40ac0a9

Browse files
committed
add annsearch API
1 parent 55f9faf commit 40ac0a9

File tree

1 file changed

+109
-0
lines changed
  • hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph

1 file changed

+109
-0
lines changed

hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/graph/VertexAPI.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
import org.apache.hugegraph.traversal.optimize.QueryHolder;
4545
import org.apache.hugegraph.traversal.optimize.Text;
4646
import org.apache.hugegraph.traversal.optimize.TraversalUtil;
47+
import org.apache.hugegraph.type.HugeType;
4748
import org.apache.hugegraph.type.define.IdStrategy;
49+
import org.apache.hugegraph.type.define.IndexType;
4850
import org.apache.hugegraph.util.E;
4951
import org.apache.hugegraph.util.JsonUtil;
5052
import org.apache.hugegraph.util.Log;
@@ -214,6 +216,83 @@ public String update(@Context GraphManager manager,
214216
return manager.serializer(g).writeVertex(vertex);
215217
}
216218

219+
@POST
220+
@Timed(name = "ann-search")
221+
@Path("annsearch")
222+
@Consumes(APPLICATION_JSON)
223+
@Produces(APPLICATION_JSON_WITH_CHARSET)
224+
@RolesAllowed({"admin", "$owner=$graph $action=vertex_read"})
225+
public String annSearch(@Context GraphManager manager,
226+
@PathParam("graph") String graph,
227+
AnnSearchRequest searchRequest) {
228+
LOG.debug("Graph [{}] ANN search with request: {}", graph, searchRequest);
229+
230+
AnnSearchRequest.checkRequest(searchRequest);
231+
232+
HugeGraph g = graph(manager, graph);
233+
234+
// Check if vertex label exists
235+
VertexLabel vertexLabel = g.vertexLabel(searchRequest.vertex_label);
236+
if (vertexLabel == null) {
237+
throw new IllegalArgumentException(
238+
"Vertex label not found: " + searchRequest.vertex_label);
239+
}
240+
241+
// Check if the property exists in the vertex label
242+
PropertyKey propertyKey = g.propertyKey(searchRequest.properties);
243+
if (propertyKey == null) {
244+
throw new IllegalArgumentException(
245+
"Property key not found: " + searchRequest.properties);
246+
}
247+
248+
// Check if the property is defined in the vertex label
249+
if (!vertexLabel.properties().contains(propertyKey.id())) {
250+
throw new IllegalArgumentException("Property '" + searchRequest.properties +
251+
"' is not defined in vertex label '" +
252+
searchRequest.vertex_label + "'");
253+
}
254+
255+
// Check if vector index exists for the property
256+
boolean hasVectorIndex = g.indexLabels().stream().anyMatch(indexLabel ->
257+
indexLabel.indexType() == IndexType.VECTOR &&
258+
indexLabel.baseType() == HugeType.VERTEX_LABEL &&
259+
indexLabel.baseValue()
260+
.equals(vertexLabel.id()) &&
261+
indexLabel.indexFields()
262+
.contains(propertyKey.id()));
263+
264+
if (!hasVectorIndex) {
265+
throw new IllegalArgumentException(
266+
"No vector index found for property '" + searchRequest.properties +
267+
"' in vertex label '" + searchRequest.vertex_label + "'");
268+
}
269+
270+
// Log query information
271+
LOG.debug(
272+
"ANN query: vertex_label={}, property={}, vector_length={}, metric={}, " +
273+
"dimension={}, hasVectorIndex={}",
274+
searchRequest.vertex_label, searchRequest.properties,
275+
searchRequest.user_vector.length,
276+
searchRequest.metric, searchRequest.dimension, hasVectorIndex);
277+
278+
try {
279+
// TODO: Here should call the actual ANN query from backend
280+
LOG.debug("ANN query not yet implemented, returning empty result");
281+
282+
// Temporary: return empty result
283+
return manager.serializer(g).writeVertices(g.traversal().V().limit(0), false);
284+
285+
// Future implementation:
286+
// 1. Call JVector engine for similarity query
287+
// 2. Return topk most similar vertices
288+
289+
} finally {
290+
if (g.tx().isOpen()) {
291+
g.tx().close();
292+
}
293+
}
294+
}
295+
217296
@GET
218297
@Timed
219298
@Compress
@@ -462,4 +541,34 @@ public String toString() {
462541
this.label, this.properties);
463542
}
464543
}
544+
545+
// ANN search request class
546+
private static class AnnSearchRequest {
547+
@JsonProperty("vertex_label")
548+
public String vertex_label;
549+
@JsonProperty("properties")
550+
public String properties;
551+
@JsonProperty("user_vector")
552+
public float[] user_vector;
553+
@JsonProperty("metric")
554+
public String metric;
555+
@JsonProperty("dimension")
556+
public Integer dimension;
557+
558+
private static void checkRequest(AnnSearchRequest req) {
559+
E.checkArgumentNotNull(req, "AnnSearchRequest can't be null");
560+
E.checkArgumentNotNull(req.vertex_label, "Parameter 'vertex_label' can't be null");
561+
E.checkArgumentNotNull(req.properties, "Parameter 'properties' can't be null");
562+
E.checkArgumentNotNull(req.user_vector, "Parameter 'user_vector' can't be null");
563+
E.checkArgument(req.user_vector.length > 0, "Parameter 'user_vector' can't be empty");
564+
E.checkArgumentNotNull(req.metric, "Parameter 'metric' can't be null");
565+
E.checkArgumentNotNull(req.dimension, "Parameter 'dimension' can't be null");
566+
}
567+
568+
@Override
569+
public String toString() {
570+
return String.format("AnnSearchRequest{vertex_label=%s, properties=%s, user_vector=%s, metric=%s, dimension=%s}",
571+
vertex_label, properties, Arrays.toString(user_vector), metric, dimension);
572+
}
573+
}
465574
}

0 commit comments

Comments
 (0)