Vector Search with Infinispan
What You Will Learn
How to store entities with vector embeddings in Infinispan and perform kNN (k-nearest neighbor) vector searches, including hybrid queries that combine vector similarity with full-text search and metadata filters.
Prerequisites
-
Java 17+
-
An Infinispan Server running on
localhost:11222(or Docker/Podman available for Testcontainers)
Step 1: Define an Indexed Entity with a Vector Field
Use the @Vector annotation to declare a vector field with its dimension and similarity function:
@Proto
@Indexed
public record Beer(
@Keyword(projectable = true, sortable = true)
String name,
@Keyword(projectable = true, normalizer = "lowercase")
String style,
@Keyword(projectable = true, sortable = true, normalizer = "lowercase")
String brewery,
@Keyword(projectable = true, normalizer = "lowercase")
String country,
@Basic(projectable = true, sortable = true)
Double abv,
@Text
String description,
@Vector(dimension = 3, similarity = VectorSimilarity.COSINE)
float[] descriptionEmbedding
) {
}
Step 2: Connect and Register the Schema
Connect to the server and register the Protobuf schema for your entity:
static void connect() throws Exception {
ConfigurationBuilder builder = TutorialsConnectorHelper.connectionConfig();
builder.addContextInitializer(new BeerSchemaImpl());
URI cacheConfigURI = VectorSearchQuickstart.class.getClassLoader()
.getResource("indexedCache.xml").toURI();
builder.remoteCache(CACHE_NAME).configurationURI(cacheConfigURI);
cacheManager = TutorialsConnectorHelper.connect(builder);
cacheManager.administration().schemas().createOrUpdate(new BeerSchemaImpl());
cache = cacheManager.getCache(CACHE_NAME);
}
Step 3: Perform a kNN Vector Search
Use the <→ operator with ~:k to find the k nearest neighbors:
static void knnVectorSearch() {
System.out.println("=== kNN: 3 beers closest to 'dark roasty' vector [0.9, 0.1, 0.1] ===");
Query<Beer> query = cache.query(
"from quickstart.Beer b where b.descriptionEmbedding <-> [:v]~:k");
query.setParameter("v", new float[]{0.9f, 0.1f, 0.1f});
query.setParameter("k", 3);
for (Beer beer : query.list()) {
System.out.printf(" %-30s %s%n", beer.name(), beer.style());
}
System.out.println();
}
Step 4: Run Hybrid Queries
Combine vector similarity with metadata filters using the filtering clause, or with full-text filters:
static void hybridFilterByStyle() {
System.out.println("=== Hybrid: closest to 'refreshing summer beer' [0.05, 0.95, 0.05], only lagers under 5% ABV ===");
Query<Object[]> query = cache.query(
"select score(b), b.name, b.style, b.abv from quickstart.Beer b " +
"where b.descriptionEmbedding <-> [:v]~:k " +
"filtering (b.style = 'Lager' and b.abv < 5.0)");
query.setParameter("v", new float[]{0.05f, 0.95f, 0.05f});
query.setParameter("k", 3);
List<Object[]> results = query.list();
if (results.isEmpty()) {
System.out.println(" (no matches)");
}
for (Object[] row : results) {
System.out.printf(" score=%.4f %-30s %-10s %.1f%%%n", row[0], row[1], row[2], row[3]);
}
System.out.println();
}
static void hybridFilterByCountry() {
System.out.println("=== Hybrid: closest to 'toasted malty caramel' [0.7, 0.3, 0.1], only Spanish beers ===");
Query<Object[]> query = cache.query(
"select score(b), b.name, b.style, b.abv from quickstart.Beer b " +
"where b.descriptionEmbedding <-> [:v]~:k filtering b.country = 'Spain'");
query.setParameter("v", new float[]{0.7f, 0.3f, 0.1f});
query.setParameter("k", 3);
for (Object[] row : query.list()) {
System.out.printf(" score=%.4f %-30s %-15s %.1f%%%n", row[0], row[1], row[2], row[3]);
}
System.out.println();
}
static void hybridFullTextAndVector() {
System.out.println("=== Hybrid: closest to 'hoppy craft' [0.1, 0.1, 0.95], description mentions 'citrus' ===");
Query<Object[]> query = cache.query(
"select score(b), b.name, b.brewery, b.abv from quickstart.Beer b " +
"where b.descriptionEmbedding <-> [:v]~:k " +
"filtering b.description : 'citrus'");
query.setParameter("v", new float[]{0.1f, 0.1f, 0.95f});
query.setParameter("k", 5);
for (Object[] row : query.list()) {
System.out.printf(" score=%.4f %-30s %-20s %.1f%%%n", row[0], row[1], row[2], row[3]);
}
System.out.println();
}
Step 5: Run the Tutorial
mvn package exec:exec
The output demonstrates full-text search, keyword/range filters, projections, kNN vector search with score projections, and hybrid queries filtering by style, country, and description text.
What’s Next
-
Semantic search with LangChain4j for vector search with an AI embedding model


