Skip to content

Commit eeed803

Browse files
committed
Camel-Qdrant: collect processors to be used as ref beans
1 parent 632c92f commit eeed803

14 files changed

Lines changed: 288 additions & 22 deletions

File tree

catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/qdrant.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"CamelQdrantWithPayload": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "true", "description": "Include Payload.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#INCLUDE_PAYLOAD" },
4646
"CamelQdrantWithVectors": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "false", "description": "Include Vectors.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#INCLUDE_VECTORS" },
4747
"CamelQdrantSize": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of elements.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#SIZE" },
48-
"CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" }
48+
"CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" },
49+
"CamelQdrantMaxResults": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The maximum number of results to return from a similarity search.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#MAX_RESULTS" }
4950
},
5051
"properties": {
5152
"collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" },

components/camel-ai/camel-qdrant/src/generated/resources/META-INF/org/apache/camel/component/qdrant/qdrant.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"CamelQdrantWithPayload": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "true", "description": "Include Payload.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#INCLUDE_PAYLOAD" },
4646
"CamelQdrantWithVectors": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "false", "description": "Include Vectors.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#INCLUDE_VECTORS" },
4747
"CamelQdrantSize": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The number of elements.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#SIZE" },
48-
"CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" }
48+
"CamelQdrantPointId": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The point id to use for operation.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#POINT_ID" },
49+
"CamelQdrantMaxResults": { "index": 10, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The maximum number of results to return from a similarity search.", "constantName": "org.apache.camel.component.qdrant.QdrantHeaders#MAX_RESULTS" }
4950
},
5051
"properties": {
5152
"collection": { "index": 0, "kind": "path", "displayName": "Collection", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The collection Name" },

components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantHeaders.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,7 @@ private QdrantHeaders() {
5555

5656
@Metadata(description = "The point id to use for operation.", javaType = "int")
5757
public static final String POINT_ID = "CamelQdrantPointId";
58+
59+
@Metadata(description = "The maximum number of results to return from a similarity search.", javaType = "int")
60+
public static final String MAX_RESULTS = "CamelQdrantMaxResults";
5861
}

components/camel-ai/camel-qdrant/src/main/java/org/apache/camel/component/qdrant/QdrantProducer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,10 @@ private boolean similaritySearch(Exchange exchange, AsyncCallback callback) thro
273273
}
274274

275275
ObjectHelper.notNull(vectors, "vectors");
276-
final int maxResults = getEndpoint().getConfiguration().getMaxResults();
276+
final int maxResults = in.getHeader(
277+
QdrantHeaders.MAX_RESULTS,
278+
getEndpoint().getConfiguration().getMaxResults(),
279+
int.class);
277280
final Common.Filter filter = getEndpoint().getConfiguration().getFilter();
278281
final Duration timeout = getEndpoint().getConfiguration().getTimeout();
279282

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.component.qdrant.rag;
18+
19+
import io.qdrant.client.grpc.Collections;
20+
import org.apache.camel.Exchange;
21+
import org.apache.camel.Processor;
22+
import org.apache.camel.component.qdrant.QdrantAction;
23+
import org.apache.camel.component.qdrant.QdrantHeaders;
24+
25+
public class RAGCreateCollection implements Processor {
26+
27+
private String size = "768";
28+
private String distance = "Cosine";
29+
30+
@Override
31+
public void process(Exchange exchange) throws Exception {
32+
int vectorSize = Integer.parseInt(size);
33+
34+
Collections.Distance distanceEnum = switch (distance.toLowerCase()) {
35+
case "cosine" -> Collections.Distance.Cosine;
36+
case "euclid" -> Collections.Distance.Euclid;
37+
case "dot" -> Collections.Distance.Dot;
38+
case "manhattan" -> Collections.Distance.Manhattan;
39+
default -> throw new IllegalArgumentException(
40+
"Unknown distance metric: " + distance + ". Supported values: Cosine, Euclid, Dot, Manhattan");
41+
};
42+
43+
Collections.VectorParams vectorParams = Collections.VectorParams.newBuilder()
44+
.setSize(vectorSize)
45+
.setDistance(distanceEnum)
46+
.build();
47+
48+
exchange.getIn().setHeader(QdrantHeaders.ACTION, QdrantAction.CREATE_COLLECTION);
49+
exchange.getIn().setBody(vectorParams);
50+
}
51+
52+
public String getSize() {
53+
return size;
54+
}
55+
56+
public void setSize(String size) {
57+
this.size = size;
58+
}
59+
60+
public String getDistance() {
61+
return distance;
62+
}
63+
64+
public void setDistance(String distance) {
65+
this.distance = distance;
66+
}
67+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.component.qdrant.rag;
18+
19+
import java.util.ArrayList;
20+
import java.util.LinkedHashMap;
21+
import java.util.List;
22+
import java.util.Map;
23+
24+
import io.qdrant.client.grpc.Points;
25+
import org.apache.camel.Exchange;
26+
27+
public class RAGResultExtractor {
28+
29+
private String payloadKey = "content";
30+
31+
@SuppressWarnings("unchecked")
32+
public List<Map<String, Object>> extract(Exchange exchange) {
33+
List<Points.ScoredPoint> results = exchange.getIn().getBody(List.class);
34+
List<Map<String, Object>> extracted = new ArrayList<>();
35+
int rank = 1;
36+
for (Points.ScoredPoint point : results) {
37+
Map<String, Object> item = new LinkedHashMap<>();
38+
item.put("rank", rank++);
39+
item.put("content", point.getPayloadMap().get(payloadKey).getStringValue());
40+
item.put("score", point.getScore());
41+
extracted.add(item);
42+
}
43+
return extracted;
44+
}
45+
46+
public String getPayloadKey() {
47+
return payloadKey;
48+
}
49+
50+
public void setPayloadKey(String payloadKey) {
51+
this.payloadKey = payloadKey;
52+
}
53+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.component.qdrant.rag;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.concurrent.atomic.AtomicLong;
22+
23+
import io.qdrant.client.PointIdFactory;
24+
import io.qdrant.client.ValueFactory;
25+
import io.qdrant.client.VectorsFactory;
26+
import io.qdrant.client.grpc.Points;
27+
import org.apache.camel.Exchange;
28+
import org.apache.camel.Processor;
29+
import org.apache.camel.component.qdrant.QdrantAction;
30+
import org.apache.camel.component.qdrant.QdrantHeaders;
31+
32+
public class RAGUpsert implements Processor {
33+
34+
private String payloadKey = "content";
35+
private String textVariable = "text";
36+
private final AtomicLong pointIdCounter = new AtomicLong(1);
37+
38+
@SuppressWarnings("unchecked")
39+
@Override
40+
public void process(Exchange exchange) throws Exception {
41+
List<Float> embedding = exchange.getIn().getBody(List.class);
42+
String text = exchange.getVariable(textVariable, String.class);
43+
44+
Points.PointStruct point = Points.PointStruct.newBuilder()
45+
.setId(PointIdFactory.id(pointIdCounter.getAndIncrement()))
46+
.setVectors(VectorsFactory.vectors(embedding))
47+
.putAllPayload(Map.of(payloadKey, ValueFactory.value(text)))
48+
.build();
49+
50+
exchange.getIn().setBody(List.of(point));
51+
exchange.getIn().setHeader(QdrantHeaders.ACTION, QdrantAction.UPSERT);
52+
}
53+
54+
public String getPayloadKey() {
55+
return payloadKey;
56+
}
57+
58+
public void setPayloadKey(String payloadKey) {
59+
this.payloadKey = payloadKey;
60+
}
61+
62+
public String getTextVariable() {
63+
return textVariable;
64+
}
65+
66+
public void setTextVariable(String textVariable) {
67+
this.textVariable = textVariable;
68+
}
69+
}

components/camel-ai/camel-qdrant/src/test/java/org/apache/camel/component/qdrant/it/QdrantComponentIT.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
import io.qdrant.client.grpc.Collections;
3030
import io.qdrant.client.grpc.Points;
3131
import org.apache.camel.Exchange;
32+
import org.apache.camel.builder.RouteBuilder;
3233
import org.apache.camel.component.qdrant.QdrantAction;
3334
import org.apache.camel.component.qdrant.QdrantActionException;
3435
import org.apache.camel.component.qdrant.QdrantHeaders;
3536
import org.apache.camel.component.qdrant.QdrantTestSupport;
37+
import org.apache.camel.component.qdrant.rag.RAGCreateCollection;
3638
import org.junit.jupiter.api.MethodOrderer;
3739
import org.junit.jupiter.api.Order;
3840
import org.junit.jupiter.api.Test;
@@ -45,6 +47,21 @@
4547
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
4648
class QdrantComponentIT extends QdrantTestSupport {
4749

50+
@Override
51+
protected RouteBuilder createRouteBuilder() {
52+
return new RouteBuilder() {
53+
@Override
54+
public void configure() {
55+
RAGCreateCollection createCollectionProcessor = new RAGCreateCollection();
56+
createCollectionProcessor.setSize("2");
57+
58+
from("direct:createCollection")
59+
.process(createCollectionProcessor)
60+
.to("qdrant:testComponent");
61+
}
62+
};
63+
}
64+
4865
@Test
4966
@Order(0)
5067
void collectionInfoNonExistent() {
@@ -69,12 +86,7 @@ void collectionInfoNonExistent() {
6986
@Test
7087
@Order(1)
7188
void createCollection() {
72-
Exchange result = fluentTemplate.to("qdrant:testComponent")
73-
.withHeader(QdrantHeaders.ACTION, QdrantAction.CREATE_COLLECTION)
74-
.withBody(
75-
Collections.VectorParams.newBuilder()
76-
.setSize(2)
77-
.setDistance(Collections.Distance.Cosine).build())
89+
Exchange result = fluentTemplate.to("direct:createCollection")
7890
.request(Exchange.class);
7991

8092
assertThat(result).isNotNull();

components/camel-ai/camel-qdrant/src/test/java/org/apache/camel/component/qdrant/it/QdrantDeleteCollectionIT.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
import io.qdrant.client.grpc.Collections;
2222
import org.apache.camel.EndpointInject;
2323
import org.apache.camel.Exchange;
24+
import org.apache.camel.builder.RouteBuilder;
2425
import org.apache.camel.component.qdrant.QdrantAction;
2526
import org.apache.camel.component.qdrant.QdrantActionException;
2627
import org.apache.camel.component.qdrant.QdrantEndpoint;
2728
import org.apache.camel.component.qdrant.QdrantHeaders;
2829
import org.apache.camel.component.qdrant.QdrantTestSupport;
30+
import org.apache.camel.component.qdrant.rag.RAGCreateCollection;
2931
import org.junit.jupiter.api.MethodOrderer;
3032
import org.junit.jupiter.api.Order;
3133
import org.junit.jupiter.api.Test;
@@ -38,15 +40,25 @@ class QdrantDeleteCollectionIT extends QdrantTestSupport {
3840
@EndpointInject("qdrant:collectionForDeletion")
3941
QdrantEndpoint qdrantEndpoint;
4042

43+
@Override
44+
protected RouteBuilder createRouteBuilder() {
45+
return new RouteBuilder() {
46+
@Override
47+
public void configure() {
48+
RAGCreateCollection createCollectionProcessor = new RAGCreateCollection();
49+
createCollectionProcessor.setSize("2");
50+
51+
from("direct:createCollection")
52+
.process(createCollectionProcessor)
53+
.to("qdrant:collectionForDeletion");
54+
}
55+
};
56+
}
57+
4158
@Test
4259
@Order(1)
4360
void createCollection() {
44-
Exchange result = fluentTemplate.to(qdrantEndpoint)
45-
.withHeader(QdrantHeaders.ACTION, QdrantAction.CREATE_COLLECTION)
46-
.withBody(
47-
Collections.VectorParams.newBuilder()
48-
.setSize(2)
49-
.setDistance(Collections.Distance.Cosine).build())
61+
Exchange result = fluentTemplate.to("direct:createCollection")
5062
.request(Exchange.class);
5163

5264
assertThat(result).isNotNull();

components/camel-ai/camel-qdrant/src/test/java/org/apache/camel/component/qdrant/it/QdrantDeletePointsIT.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
import io.qdrant.client.PointIdFactory;
2525
import io.qdrant.client.ValueFactory;
2626
import io.qdrant.client.VectorsFactory;
27-
import io.qdrant.client.grpc.Collections;
2827
import io.qdrant.client.grpc.Common;
2928
import io.qdrant.client.grpc.Points;
3029
import org.apache.camel.Exchange;
30+
import org.apache.camel.builder.RouteBuilder;
3131
import org.apache.camel.component.qdrant.QdrantAction;
3232
import org.apache.camel.component.qdrant.QdrantHeaders;
3333
import org.apache.camel.component.qdrant.QdrantTestSupport;
34+
import org.apache.camel.component.qdrant.rag.RAGCreateCollection;
3435
import org.junit.jupiter.api.MethodOrderer;
3536
import org.junit.jupiter.api.Order;
3637
import org.junit.jupiter.api.Test;
@@ -40,15 +41,26 @@
4041

4142
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
4243
class QdrantDeletePointsIT extends QdrantTestSupport {
44+
45+
@Override
46+
protected RouteBuilder createRouteBuilder() {
47+
return new RouteBuilder() {
48+
@Override
49+
public void configure() {
50+
RAGCreateCollection createCollectionProcessor = new RAGCreateCollection();
51+
createCollectionProcessor.setSize("2");
52+
53+
from("direct:createCollection")
54+
.process(createCollectionProcessor)
55+
.to("qdrant:testDelete");
56+
}
57+
};
58+
}
59+
4360
@Test
4461
@Order(1)
4562
void createCollection() {
46-
Exchange result = fluentTemplate.to("qdrant:testDelete")
47-
.withHeader(QdrantHeaders.ACTION, QdrantAction.CREATE_COLLECTION)
48-
.withBody(
49-
Collections.VectorParams.newBuilder()
50-
.setSize(2)
51-
.setDistance(Collections.Distance.Cosine).build())
63+
Exchange result = fluentTemplate.to("direct:createCollection")
5264
.request(Exchange.class);
5365

5466
assertThat(result).isNotNull();

0 commit comments

Comments
 (0)