Embeddings och hämtning från vektorlagring
Generera embeddings och fråga vektorlagringar för att möjliggöra semantisk sökning i dina data.
Embeddings och hämtning från vektorlagring är en gratis lektion i Spring Boot 4 – komplett guide på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Spring Boot 4 – komplett guide, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Spring Boot 4 – komplett guide innehåller totalt 4 lektioner.
Varför embeddings möjliggör semantisk sökning
Nyckelordssökning matchar bokstavliga token. Semantisk sökning matchar betydelse. Bryggan mellan de två är en embedding: en vektor med flyttal och fast längd som fångar det semantiska innehållet i en text.
- Texter med liknande betydelse ger vektorer som ligger nära varandra i vektorrummet.
- Närheten mäts med cosine similarity eller euklidiskt avstånd.
- En fråga som
"how do I reset my password"kan matcha ett dokument med rubriken"account recovery steps"även om de inte har ett enda gemensamt nyckelord.
I Spring AI genererar ni embeddings med en EmbeddingModel och lagrar och frågar efter dem med en VectorStore. Den här lektionen kopplar ihop båda i en Retrieval-Augmented-pipeline.
Abstraktionen EmbeddingModel
Spring AI tillhandahåller EmbeddingModel som ett leverantörsoberoende gränssnitt. Lägg till starter-paketet (till exempel spring-ai-starter-model-openai), så autokonfigurerar Spring Boot en bean som ni kan injicera.
embed(String)returnerar en enskildfloat[].embed(List<String>)batchar flera texter effektivt.dimensions()anger vektorns storlek (till exempel 1536 förtext-embedding-3-small).
Konfigurera modellen i application.yml så att beanen är klar för injicering.
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
embedding:
options:
model: text-embedding-3-smallGenerera er första embedding
Injicera EmbeddingModel och anropa embed. Resultatet är en tät vektor som ni kan inspektera eller spara. Det mer omfattande anropet embedForResponse returnerar även metadata om tokenanvändningen.
- Logga alltid
dimensions()en gång vid uppstart så att ett modellbyte som ändrar vektorns storlek upptäcks tidigt. - En kolumn i ett vektorlager måste ha exakt samma dimension, annars misslyckas infogningen.
@RestController
class EmbeddingController {
private final EmbeddingModel embeddingModel;
EmbeddingController(EmbeddingModel embeddingModel) {
this.embeddingModel = embeddingModel;
}
@GetMapping("/embed")
Map<String, Object> embed(@RequestParam String text) {
float[] vector = embeddingModel.embed(text);
return Map.of(
"dimensions", vector.length,
"preview", List.of(vector[0], vector[1], vector[2])
);
}
}Cosine similarity för hand
För att bygga upp en intuitiv förståelse ser ni här den matematik som ett vektorlager utför åt er. Cosine similarity är skalärprodukten av två vektorer dividerad med produkten av deras magnituder. Värdet sträcker sig från -1 (motsatt riktning) till 1 (identisk riktning).
- Ett värde nära 1.0 betyder att texterna är semantiskt mycket lika.
- Vektorlager visar vanligtvis ett likhetspoäng som härleds från detta mått.
Det här fristående programmet beräknar cosine similarity för två exempelvektorer.
public class CosineSimilarity {
static double cosine(double[] a, double[] b) {
double dot = 0, normA = 0, normB = 0;
for (int i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
public static void main(String[] args) {
double[] query = {0.9, 0.1, 0.2};
double[] docA = {0.8, 0.2, 0.1};
double[] docB = {-0.5, 0.9, -0.4};
System.out.printf("query vs A: %.4f%n", cosine(query, docA));
System.out.printf("query vs B: %.4f%n", cosine(query, docB));
}
}Abstraktionen VectorStore
En VectorStore lagrar Document-objekt tillsammans med deras embeddings och stöder likhetsfrågor. Spring AI levereras med implementationer för PGVector, Redis, Chroma, Milvus och Qdrant samt en SimpleVectorStore för tester.
add(List<Document>)skapar embeddings för och lagrar dokument.similaritySearch(SearchRequest)skapar en embedding av frågan och returnerar de närmaste dokumenten.delete(...)tar bort dokument efter id eller filter.
Viktigt är att add anropar EmbeddingModel åt er, så vid användning av ett lager behöver ni sällan skapa embeddings manuellt.
Konfigurera PGVector
För produktion är PGVector (Postgres-tillägget) ett vanligt val eftersom vektorerna lagras tillsammans med era relationsdata. Lägg till spring-ai-starter-vector-store-pgvector och konfigurera initieringen av schemat.
index-type: HNSWger snabb approximerad sökning efter närmaste grannar.dimensionsmåste motsvara utmatningsstorleken hos er embeddingmodell.initialize-schema: truelåter Spring skapa tabellenvector_storevid uppstart.
spring:
ai:
vectorstore:
pgvector:
initialize-schema: true
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1536
datasource:
url: jdbc:postgresql://localhost:5432/appdb
username: app
password: ${DB_PASSWORD}Läsa in dokument
Omslut varje del av källtexten i ett Document. Ni kan lägga till valfria metadata (källa, författare, klient-id) som kan användas i filter vid frågor. Anropet vectorStore.add(...) skapar embeddings och lagrar dem i ett enda steg.
- Använd ett stabilt id när ni vill uppdatera eller infoga på nytt i stället för att skapa dubbletter.
- Håll delarna små (några hundra token) så att den hämtade kontexten förblir fokuserad.
@Service
class IngestionService {
private final VectorStore vectorStore;
IngestionService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
void ingest() {
List<Document> docs = List.of(
new Document("Spring Boot 4 requires Java 17 or later.",
Map.of("source", "release-notes", "version", "4.0")),
new Document("Reset your password from the account recovery page.",
Map.of("source", "help-center", "topic", "auth"))
);
vectorStore.add(docs);
}
}Dela upp med ETL-läsare
Verkliga textkorpusar kommer som PDF, Markdown eller JSON. Spring AI:s ETL-pipeline tillhandahåller källor av typen DocumentReader och uppdelare av typen DocumentTransformer. TokenTextSplitter delar upp stora dokument i delar anpassade för embeddings samtidigt som metadata bevaras.
TikaDocumentReaderläser PDF, Word och HTML.TokenTextSplitterdelar upp efter tokenantal med konfigurerbart överlapp.- Resultatet skickas direkt vidare till
vectorStore.add(...).
@Service
class PdfIngestion {
private final VectorStore vectorStore;
PdfIngestion(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
void load(Resource pdf) {
var reader = new TikaDocumentReader(pdf);
var splitter = new TokenTextSplitter();
List<Document> chunks = splitter.apply(reader.get());
vectorStore.add(chunks);
}
}Likhetssökning med SearchRequest
SearchRequest är en builder som styr hämtningen. De viktigaste reglagen är topK (antal resultat) och similarityThreshold (svaga matchningar under en gräns tas bort).
- Ett högre
similarityThreshold(till exempel 0.75) minskar brus men kan ge färre träffar. topKbegränsar hur mycket kontext ni skickar till LLM:en, vilket styr tokenkostnaden.
@Service
class SearchService {
private final VectorStore vectorStore;
SearchService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
List<Document> search(String query) {
return vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.topK(4)
.similarityThreshold(0.7)
.build()
);
}
}Metadatafiltrering
Semantisk relevans räcker inte för data som är uppdelad mellan flera klienter eller avgränsad på annat sätt. SearchRequest accepterar ett filteruttryck som utvärderas mot dokumentens metadata och kombinerar vektorsimilaritet med strukturerade begränsningar.
- Använd
FilterExpressionBuildereller ett portabelt stränguttryck. - Lagret tillämpar filtret och likhetsrankningen tillsammans.
- Så här upprätthåller ni klientisolering:
tenantId == 'acme'.
List<Document> scoped = vectorStore.similaritySearch(
SearchRequest.builder()
.query("how do I reset my password")
.topK(3)
.similarityThreshold(0.7)
.filterExpression("source == 'help-center' && topic == 'auth'")
.build()
);Från hämtning till RAG
Hämtning är den första halvan av RAG (Retrieval-Augmented Generation). Den andra halvan lägger in de hämtade delarna i prompten så att LLM:en svarar med stöd i era data. Spring AI:s QuestionAnswerAdvisor kopplar vektorlagret direkt till ett ChatClient-anrop.
- Advisorn kör en likhetssökning per begäran och lägger in resultaten som kontext.
- Ni skickar in samma inställningar för
SearchRequest(topK, threshold) till advisorn. - Det gör svaret troget era indexerade dokument och minskar hallucinationer.
@Service
class RagService {
private final ChatClient chatClient;
RagService(ChatClient.Builder builder, VectorStore vectorStore) {
this.chatClient = builder
.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().topK(4).similarityThreshold(0.7).build())
.build())
.build();
}
String ask(String question) {
return chatClient.prompt().user(question).call().content();
}
}Snabbkontroll: justera hämtningen
En kollega rapporterar att deras RAG-endpoint ofta lägger in irrelevanta dokument i prompten, vilket ökar tokenkostnaden och förvirrar modellen. De vill bara behålla starkt relevanta matchningar utan att ändra embeddingmodellen. Vilken enskild justering av SearchRequest åtgärdar detta mest direkt?
Sammanfattning och viktiga slutsatser
Ni har byggt en komplett pipeline för semantisk hämtning i Spring AI:
- EmbeddingModel omvandlar text till täta vektorer;
dimensions()måste matcha storleken på kolumnen i lagret. - VectorStore (PGVector, Redis, Qdrant med flera) lagrar
Document-objekt och skapar automatiskt embeddings för dem vidadd(). - Använd ETL-pipelinen (
TikaDocumentReader+TokenTextSplitter) för att dela upp verkliga filer före inläsningen. - SearchRequest styr hämtningen via
topK,similarityThresholdoch metadatafältetfilterExpressionför avgränsning och klientisolering. - QuestionAnswerAdvisor omvandlar hämtningen till fullständig RAG genom att lägga in matchande kontext i en
ChatClient-prompt.
Justera topK för kostnad och similarityThreshold för precision för att balansera förankring mot tokenbudgeten.
Lär dig Java med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 21
- Lektioner
- 84
Vanliga frågor
Är lektionen ”Embeddings och hämtning från vektorlagring” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Spring Boot 4 – komplett guide, inklusive ”Embeddings och hämtning från vektorlagring”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Spring Boot 4 – komplett guide innehåller totalt 4 lektioner.
Vad lär jag mig i ”Embeddings och hämtning från vektorlagring”?
Generera embeddings och fråga vektorlagringar för att möjliggöra semantisk sökning i dina data. Ni övar på Spring Boot 4 – komplett guide med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Spring Boot 4 – komplett guide?
Du behöver inga förkunskaper. Utbildningen i Spring Boot 4 – komplett guide på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Embeddings och hämtning från vektorlagring”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Spring Boot 4 – komplett guide-lektionen?
Ja. Varje Spring Boot 4 – komplett guide-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- ChatClient, promptar och strukturerade utdata
- Embeddings och hämtning från vektorlagring
- Pipelines för Retrieval-Augmented Generation
- Verktygsanrop och agentrådgivare