From 6ac29ac4bd90375277d614af1c76e3f5f01d86d0 Mon Sep 17 00:00:00 2001 From: zaojiankongli <164828112+zaojiankongli@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:50:38 +0800 Subject: [PATCH] Add files via upload --- VectorGraphRag/pom.xml | 103 +++ .../zjkl/vectorgraphrag/VectorGraphRAG.java | 451 +++++++++++++ .../config/VectorGraphRagSettings.java | 110 ++++ .../com/zjkl/vectorgraphrag/graph/Graph.java | 258 ++++++++ .../vectorgraphrag/graph/GraphBuilder.java | 200 ++++++ .../vectorgraphrag/graph/GraphRetriever.java | 237 +++++++ .../zjkl/vectorgraphrag/graph/SubGraph.java | 298 +++++++++ .../vectorgraphrag/graph/SubGraphEntity.java | 22 + .../vectorgraphrag/graph/SubGraphPassage.java | 22 + .../graph/SubGraphRelation.java | 25 + .../vectorgraphrag/llm/AnswerGenerator.java | 45 ++ .../vectorgraphrag/llm/EntityExtractor.java | 82 +++ .../com/zjkl/vectorgraphrag/llm/LLMCache.java | 74 +++ .../zjkl/vectorgraphrag/llm/LLMReranker.java | 180 +++++ .../zjkl/vectorgraphrag/llm/OpenAiClient.java | 281 ++++++++ .../vectorgraphrag/llm/TripletExtractor.java | 107 +++ .../zjkl/vectorgraphrag/model/Document.java | 24 + .../com/zjkl/vectorgraphrag/model/Entity.java | 31 + .../vectorgraphrag/model/EvictionResult.java | 19 + .../model/ExtractionResult.java | 28 + .../zjkl/vectorgraphrag/model/Passage.java | 23 + .../vectorgraphrag/model/QueryResult.java | 34 + .../zjkl/vectorgraphrag/model/Relation.java | 22 + .../vectorgraphrag/model/RerankResult.java | 20 + .../vectorgraphrag/model/RetrievalDetail.java | 28 + .../vectorgraphrag/model/RetrievalResult.java | 43 ++ .../zjkl/vectorgraphrag/model/Triplet.java | 40 ++ .../storage/EmbeddingClient.java | 92 +++ .../vectorgraphrag/storage/MilvusStore.java | 621 ++++++++++++++++++ .../zjkl/vectorgraphrag/VectorGraphRAG.class | Bin 0 -> 21555 bytes ...ttings$VectorGraphRagSettingsBuilder.class | Bin 0 -> 11253 bytes .../config/VectorGraphRagSettings.class | Bin 0 -> 18214 bytes .../com/zjkl/vectorgraphrag/graph/Graph.class | Bin 0 -> 12731 bytes .../vectorgraphrag/graph/GraphBuilder.class | Bin 0 -> 12509 bytes .../vectorgraphrag/graph/GraphRetriever.class | Bin 0 -> 13763 bytes .../zjkl/vectorgraphrag/graph/SubGraph.class | Bin 0 -> 14527 bytes ...SubGraphEntity$SubGraphEntityBuilder.class | Bin 0 -> 2922 bytes .../vectorgraphrag/graph/SubGraphEntity.class | Bin 0 -> 4495 bytes ...bGraphPassage$SubGraphPassageBuilder.class | Bin 0 -> 2933 bytes .../graph/SubGraphPassage.class | Bin 0 -> 4496 bytes ...raphRelation$SubGraphRelationBuilder.class | Bin 0 -> 3486 bytes .../graph/SubGraphRelation.class | Bin 0 -> 6052 bytes .../vectorgraphrag/llm/AnswerGenerator.class | Bin 0 -> 2584 bytes .../vectorgraphrag/llm/EntityExtractor.class | Bin 0 -> 3979 bytes .../zjkl/vectorgraphrag/llm/LLMCache.class | Bin 0 -> 4343 bytes .../zjkl/vectorgraphrag/llm/LLMReranker.class | Bin 0 -> 10963 bytes .../vectorgraphrag/llm/OpenAiClient.class | Bin 0 -> 13597 bytes .../vectorgraphrag/llm/TripletExtractor.class | Bin 0 -> 7647 bytes .../model/Document$DocumentBuilder.class | Bin 0 -> 3145 bytes .../zjkl/vectorgraphrag/model/Document.class | Bin 0 -> 4761 bytes .../model/Entity$EntityBuilder.class | Bin 0 -> 2191 bytes .../zjkl/vectorgraphrag/model/Entity.class | Bin 0 -> 3012 bytes ...EvictionResult$EvictionResultBuilder.class | Bin 0 -> 2321 bytes .../vectorgraphrag/model/EvictionResult.class | Bin 0 -> 2952 bytes ...actionResult$ExtractionResultBuilder.class | Bin 0 -> 4434 bytes .../model/ExtractionResult.class | Bin 0 -> 6531 bytes .../model/Passage$PassageBuilder.class | Bin 0 -> 3156 bytes .../zjkl/vectorgraphrag/model/Passage.class | Bin 0 -> 5137 bytes .../QueryResult$QueryResultBuilder.class | Bin 0 -> 5961 bytes .../vectorgraphrag/model/QueryResult.class | Bin 0 -> 10596 bytes .../model/Relation$RelationBuilder.class | Bin 0 -> 3181 bytes .../zjkl/vectorgraphrag/model/Relation.class | Bin 0 -> 5173 bytes .../RerankResult$RerankResultBuilder.class | Bin 0 -> 2533 bytes .../vectorgraphrag/model/RerankResult.class | Bin 0 -> 3639 bytes ...trievalDetail$RetrievalDetailBuilder.class | Bin 0 -> 4158 bytes .../model/RetrievalDetail.class | Bin 0 -> 6518 bytes ...trievalResult$RetrievalResultBuilder.class | Bin 0 -> 7200 bytes .../model/RetrievalResult.class | Bin 0 -> 11503 bytes .../model/Triplet$TripletBuilder.class | Bin 0 -> 1840 bytes .../zjkl/vectorgraphrag/model/Triplet.class | Bin 0 -> 2825 bytes .../storage/EmbeddingClient.class | Bin 0 -> 4729 bytes .../vectorgraphrag/storage/MilvusStore.class | Bin 0 -> 34069 bytes .../compile/default-compile/createdFiles.lst | 43 ++ .../compile/default-compile/inputFiles.lst | 28 + 74 files changed, 3591 insertions(+) create mode 100644 VectorGraphRag/pom.xml create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/VectorGraphRAG.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/Graph.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphBuilder.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphRetriever.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraph.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphEntity.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphPassage.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphRelation.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/AnswerGenerator.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/EntityExtractor.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMCache.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMReranker.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/OpenAiClient.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/TripletExtractor.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Document.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Entity.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/EvictionResult.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/ExtractionResult.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Passage.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/QueryResult.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Relation.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RerankResult.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalDetail.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalResult.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Triplet.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/EmbeddingClient.java create mode 100644 VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/MilvusStore.java create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/VectorGraphRAG.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings$VectorGraphRagSettingsBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/Graph.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/GraphBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/GraphRetriever.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraph.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphEntity$SubGraphEntityBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphEntity.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage$SubGraphPassageBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation$SubGraphRelationBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/AnswerGenerator.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/EntityExtractor.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/LLMCache.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/LLMReranker.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/OpenAiClient.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/TripletExtractor.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Document$DocumentBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Document.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Entity$EntityBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Entity.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/EvictionResult$EvictionResultBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/EvictionResult.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/ExtractionResult$ExtractionResultBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/ExtractionResult.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Passage$PassageBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Passage.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult$QueryResultBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Relation$RelationBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Relation.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RerankResult$RerankResultBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RerankResult.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalDetail$RetrievalDetailBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalDetail.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalResult$RetrievalResultBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalResult.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet$TripletBuilder.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/storage/EmbeddingClient.class create mode 100644 VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/storage/MilvusStore.class create mode 100644 VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst diff --git a/VectorGraphRag/pom.xml b/VectorGraphRag/pom.xml new file mode 100644 index 0000000..c28d0b1 --- /dev/null +++ b/VectorGraphRag/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + com.zjkl + vector-graph-rag + 0.1.0 + jar + Vector Graph RAG + Graph RAG using pure vector search with Milvus + + + 21 + 21 + 21 + UTF-8 + 3.5.11 + 2.6.18 + 2.13.2 + 3.2.0 + 1.18.44 + 2.0.17 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + io.milvus + milvus-sdk-java + ${milvus-sdk.version} + + + + com.google.code.gson + gson + ${gson.version} + + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + 21 + 21 + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/VectorGraphRAG.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/VectorGraphRAG.java new file mode 100644 index 0000000..8cba48a --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/VectorGraphRAG.java @@ -0,0 +1,451 @@ +package com.zjkl.vectorgraphrag; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.graph.Graph; +import com.zjkl.vectorgraphrag.graph.GraphBuilder; +import com.zjkl.vectorgraphrag.graph.GraphRetriever; +import com.zjkl.vectorgraphrag.graph.SubGraph; +import com.zjkl.vectorgraphrag.llm.AnswerGenerator; +import com.zjkl.vectorgraphrag.llm.EntityExtractor; +import com.zjkl.vectorgraphrag.llm.LLMCache; +import com.zjkl.vectorgraphrag.llm.LLMReranker; +import com.zjkl.vectorgraphrag.llm.OpenAiClient; +import com.zjkl.vectorgraphrag.llm.TripletExtractor; +import com.zjkl.vectorgraphrag.model.*; +import com.zjkl.vectorgraphrag.storage.EmbeddingClient; +import com.zjkl.vectorgraphrag.storage.MilvusStore; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Vector Graph RAG - Graph RAG using pure vector search with Milvus. + * + * Main entry point for building and querying a Graph RAG system. + * Implements the full pipeline: triplet extraction → graph building → + * embedding → Milvus indexing → multi-way retrieval → subgraph expansion → + * LLM reranking → answer generation. + * + * Example: + *
{@code
+ * VectorGraphRagSettings settings = VectorGraphRagSettings.builder()
+ *     .openaiApiKey(System.getenv("OPENAI_API_KEY"))
+ *     .milvusUri("./my_graph.db")
+ *     .build();
+ *
+ * VectorGraphRAG rag = new VectorGraphRAG(settings);
+ *
+ * rag.addTexts(List.of(
+ *     "Albert Einstein developed the theory of relativity.",
+ *     "The theory of relativity revolutionized physics."
+ * ));
+ *
+ * QueryResult result = rag.query("What did Einstein develop?");
+ * System.out.println(result.getAnswer());
+ * }
+ */ +@Slf4j +public class VectorGraphRAG { + + private final VectorGraphRagSettings settings; + + private final EmbeddingClient embeddingClient; + private final MilvusStore store; + private final GraphBuilder graphBuilder; + private final TripletExtractor tripletExtractor; + private final EntityExtractor entityExtractor; + private final LLMReranker reranker; + private final AnswerGenerator answerGenerator; + private final LLMCache llmCache; + private final OpenAiClient openAiClient; + private final Graph graph; + + @Getter + private GraphRetriever retriever; + + @Getter + private ExtractionResult extractionResult; + + /** + * Create VectorGraphRAG with custom settings. + */ + public VectorGraphRAG(VectorGraphRagSettings settings) { + this.settings = settings; + this.llmCache = settings.isUseLlmCache() ? new LLMCache() : null; + this.openAiClient = new OpenAiClient(settings, llmCache); + this.embeddingClient = new EmbeddingClient(settings, openAiClient); + this.store = new MilvusStore(settings, embeddingClient); + this.graphBuilder = new GraphBuilder(settings); + this.tripletExtractor = new TripletExtractor(settings, openAiClient); + this.entityExtractor = new EntityExtractor(settings, openAiClient); + this.reranker = new LLMReranker(settings, openAiClient); + this.answerGenerator = new AnswerGenerator(settings, openAiClient); + this.graph = new Graph(settings, store, embeddingClient); + + // Create collections if they don't exist + store.createCollections(false); + } + + /** + * Create VectorGraphRAG with default settings (reads OPENAI_API_KEY from environment). + */ + public static VectorGraphRAG createDefault() { + VectorGraphRagSettings settings = VectorGraphRagSettings.builder() + .openaiApiKey(System.getenv().getOrDefault("OPENAI_API_KEY", "")) + .build(); + return new VectorGraphRAG(settings); + } + + // ==================== Indexing ==================== + + /** + * Add text strings to the knowledge base. + */ + public ExtractionResult addTexts(List texts) { + return addTexts(texts, null, true); + } + + /** + * Add text strings with extraction control. + */ + public ExtractionResult addTexts(List texts, List ids, boolean extractTriplets) { + List documents = new ArrayList<>(); + for (int i = 0; i < texts.size(); i++) { + String docId = (ids != null && i < ids.size()) ? ids.get(i) : UUID.randomUUID().toString(); + documents.add(Document.builder() + .id(docId) + .text(texts.get(i)) + .build()); + } + return addDocuments(documents, extractTriplets, true); + } + + /** + * Add Document objects to the knowledge base. + * Full indexing pipeline: extract triplets → build graph → embed → index in Milvus. + */ + public ExtractionResult addDocuments(List documents, boolean extractTriplets, boolean showProgress) { + // Ensure all documents have IDs + for (Document doc : documents) { + if (doc.getId() == null) { + doc.setId(UUID.randomUUID().toString()); + } + } + + // Extract triplets + if (extractTriplets) { + documents = tripletExtractor.extractFromDocuments(documents, showProgress); + } + + // Build graph + this.extractionResult = graphBuilder.buildFromDocuments(documents); + + // Generate embeddings + if (showProgress) log.info("Generating embeddings..."); + + List entityTexts = graphBuilder.getEntityTexts(); + List relationTexts = graphBuilder.getRelationTexts(); + List passageTexts = graphBuilder.getPassageTexts(); + + List> entityEmbeddings = entityTexts.isEmpty() ? List.of() + : embeddingClient.embedBatch(entityTexts, showProgress); + List> relationEmbeddings = relationTexts.isEmpty() ? List.of() + : embeddingClient.embedBatch(relationTexts, showProgress); + List> passageEmbeddings = passageTexts.isEmpty() ? List.of() + : embeddingClient.embedBatch(passageTexts, showProgress); + + // Build metadata for adjacency + List> entityMetadatas = new ArrayList<>(); + for (String eid : graphBuilder.getEntityIds()) { + Map meta = new HashMap<>(); + meta.put("relation_ids", graphBuilder.getEntityToRelationIds() + .getOrDefault(eid, List.of())); + meta.put("passage_ids", graphBuilder.getEntityToPassageIds() + .getOrDefault(eid, List.of())); + entityMetadatas.add(meta); + } + + List> relationMetadatas = new ArrayList<>(); + for (String rid : graphBuilder.getRelationIds()) { + Map meta = new HashMap<>(); + meta.put("entity_ids", graphBuilder.getRelationToEntityIds() + .getOrDefault(rid, List.of())); + meta.put("passage_ids", graphBuilder.getRelationToPassageIds() + .getOrDefault(rid, List.of())); + + Triplet triplet = graphBuilder.getRelationIdToTriplet().get(rid); + if (triplet != null) { + meta.put("subject", triplet.getSubject()); + meta.put("predicate", triplet.getPredicate()); + meta.put("object", triplet.getObject()); + } + relationMetadatas.add(meta); + } + + List> passageMetadatas = new ArrayList<>(); + for (String pid : graphBuilder.getPassageIds()) { + Map meta = new HashMap<>(); + meta.put("entity_ids", graphBuilder.getPassageToEntityIds() + .getOrDefault(pid, List.of())); + meta.put("relation_ids", graphBuilder.getPassageToRelationIds() + .getOrDefault(pid, List.of())); + passageMetadatas.add(meta); + } + + // Drop and recreate for idempotent indexing (matching Python reference behavior) + store.dropCollections(); + store.createCollections(true); + if (showProgress) log.info("Inserting into Milvus..."); + + store.insertEntities(entityTexts, graphBuilder.getEntityIds(), + entityEmbeddings, entityMetadatas, showProgress); + store.insertRelations(relationTexts, graphBuilder.getRelationIds(), + relationEmbeddings, relationMetadatas, showProgress); + store.insertPassages(passageTexts, graphBuilder.getPassageIds(), + passageEmbeddings, passageMetadatas, showProgress); + + // Reset retriever + this.retriever = null; + + return extractionResult; + } + + /** + * Add documents with pre-extracted triplets (skip LLM extraction). + */ + public ExtractionResult addDocumentsWithTriplets(List> documents) { + List docs = new ArrayList<>(); + for (Map docData : documents) { + String passage = (String) docData.getOrDefault("passage", docData.get("text")); + if (passage == null) { + throw new IllegalArgumentException("Each document must include 'passage' or 'text'"); + } + + String docId = (String) docData.getOrDefault("id", UUID.randomUUID().toString()); + + @SuppressWarnings("unchecked") + List> rawTriplets = (List>) docData.get("triplets"); + List triplets = new ArrayList<>(); + if (rawTriplets != null) { + for (List raw : rawTriplets) { + if (raw.size() >= 3) { + triplets.add(new Triplet(raw.get(0), raw.get(1), raw.get(2))); + } + } + } + + Document doc = Document.builder() + .id(docId) + .text(passage) + .triplets(triplets) + .build(); + // Store triplets in metadata for graph builder + List> metadataTriplets = triplets.stream() + .map(t -> List.of(t.getSubject(), t.getPredicate(), t.getObject())) + .collect(Collectors.toList()); + doc.getMetadata().put("triplets", metadataTriplets); + + docs.add(doc); + } + + return addDocuments(docs, false, true); + } + + // ==================== Query ==================== + + /** + * Full Graph RAG query pipeline. + */ + public QueryResult query(String question) { + return query(question, true, null, null, null, null, null); + } + + /** + * Query with custom parameters. + */ + public QueryResult query(String question, boolean useReranking, + Integer entityTopK, Integer relationTopK, + Float entitySimilarityThreshold, Float relationSimilarityThreshold, + String filter) { + GraphRetriever ret = getOrCreateRetriever(); + + RetrievalResult retrievalResult = ret.retrieve(question, entityTopK, relationTopK, + entitySimilarityThreshold, relationSimilarityThreshold, + null, filter); + + // Build retrieval detail + RetrievalDetail retrievalDetail = RetrievalDetail.builder() + .entityIds(retrievalResult.getEntityIds()) + .entityTexts(retrievalResult.getEntityTexts()) + .entityScores(retrievalResult.getEntityScores()) + .relationIds(retrievalResult.getRelationIds()) + .relationTexts(retrievalResult.getRelationTexts()) + .relationScores(retrievalResult.getRelationScores()) + .build(); + + // Get candidate relations from subgraph + List candidateIds = retrievalResult.getExpandedRelationIds(); + List candidateTexts = retrievalResult.getExpandedRelationTexts(); + + // Rerank + RerankResult rerankResult = null; + List rerankedIds; + List rerankedTexts; + + if (useReranking && !candidateIds.isEmpty()) { + Map.Entry, List> result = reranker.rerank( + question, candidateIds, candidateTexts); + rerankedIds = result.getKey(); + rerankedTexts = result.getValue(); + rerankResult = RerankResult.builder() + .selectedRelationIds(rerankedIds) + .selectedRelationTexts(rerankedTexts) + .build(); + } else { + rerankedIds = candidateIds.size() > settings.getFinalTopK() + ? candidateIds.subList(0, settings.getFinalTopK()) + : candidateIds; + rerankedTexts = candidateTexts.size() > settings.getFinalTopK() + ? candidateTexts.subList(0, settings.getFinalTopK()) + : candidateTexts; + } + + // Get passages from reranked relations + List finalPassages = getPassagesFromRelations(rerankedIds, filter); + + // Hybrid fallback: if graph retrieval yields fewer passages than needed, + // supplement with naive vector search on passages directly + if (finalPassages.size() < settings.getFinalTopK()) { + int needed = settings.getFinalTopK() - finalPassages.size(); + Set existing = new HashSet<>(finalPassages); + List naivePassages = ret.retrievePassagesNaive(question, needed, filter); + for (String p : naivePassages) { + if (existing.add(p)) { + finalPassages.add(p); + if (finalPassages.size() >= settings.getFinalTopK()) break; + } + } + } + + if (finalPassages.size() > settings.getFinalTopK()) { + finalPassages = finalPassages.subList(0, settings.getFinalTopK()); + } + + // Generate answer + String answer = answerGenerator.generate(question, finalPassages); + + return QueryResult.builder() + .query(question) + .answer(answer) + .queryEntities(retrievalResult.getQueryEntities()) + .retrievedPassages(finalPassages) + .retrievedRelations(retrievalResult.getRelationTexts()) + .expandedRelations(candidateTexts) + .rerankedRelations(rerankedTexts) + .subgraph(retrievalResult.getSubgraph()) + .passages(finalPassages) + .retrievalDetail(retrievalDetail) + .rerankResult(rerankResult) + .evictionResult(EvictionResult.builder() + .occurred(retrievalResult.isEvictionOccurred()) + .beforeCount(retrievalResult.getEvictionBeforeCount()) + .afterCount(retrievalResult.getEvictionAfterCount()) + .build()) + .build(); + } + + /** + * Simple query that returns just the answer string. + */ + public String querySimple(String question) { + return query(question).getAnswer(); + } + + /** + * Naive RAG query (direct passage retrieval, no graph). + */ + public QueryResult queryNaive(String question, String filter) { + GraphRetriever ret = getOrCreateRetriever(); + List passages = ret.retrievePassagesNaive(question, settings.getFinalTopK(), filter); + String answer = answerGenerator.generate(question, passages); + + return QueryResult.builder() + .query(question) + .answer(answer) + .retrievedPassages(passages) + .build(); + } + + // ==================== Utility ==================== + + /** + * Get passages associated with given relation IDs. + */ + private List getPassagesFromRelations(List relationIds, String filter) { + if (relationIds == null || relationIds.isEmpty()) return List.of(); + + List> relationData = store.getRelationsByIds(relationIds); + Set passageIds = new LinkedHashSet<>(); + for (Map rel : relationData) { + @SuppressWarnings("unchecked") + List pids = (List) rel.get("passage_ids"); + if (pids != null) passageIds.addAll(pids); + } + + if (passageIds.isEmpty()) return List.of(); + + List> passageData = store.getPassagesByIds(new ArrayList<>(passageIds), filter); + Map idToText = new LinkedHashMap<>(); + for (Map p : passageData) { + idToText.put(p.get("id").toString(), p.get("text").toString()); + } + + return passageIds.stream() + .map(idToText::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * Get knowledge base statistics. + */ + public Map getStats() { + if (extractionResult == null) { + Map stats = new HashMap<>(); + stats.put("entities", 0); + stats.put("relations", 0); + stats.put("passages", 0); + return stats; + } + Map stats = new HashMap<>(); + stats.put("entities", extractionResult.getEntities().size()); + stats.put("relations", extractionResult.getRelations().size()); + stats.put("passages", extractionResult.getDocuments().size()); + return stats; + } + + /** + * Reset the knowledge base, removing all data. + */ + public void reset() { + store.dropCollections(); + store.createCollections(true); + this.extractionResult = null; + this.retriever = null; + } + + private GraphRetriever getOrCreateRetriever() { + if (retriever == null) { + retriever = new GraphRetriever(settings, store, embeddingClient, entityExtractor); + } + return retriever; + } + + // ==================== Accessors ==================== + + public Graph getGraph() { return graph; } + public MilvusStore getStore() { return store; } + public EmbeddingClient getEmbeddingClient() { return embeddingClient; } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings.java new file mode 100644 index 0000000..170a334 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/config/VectorGraphRagSettings.java @@ -0,0 +1,110 @@ +package com.zjkl.vectorgraphrag.config; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Component +public class VectorGraphRagSettings { + // OpenAI Settings + @Builder.Default + private String openaiApiKey = System.getenv().getOrDefault("OPENAI_API_KEY", ""); + + @Builder.Default + private String openaiBaseUrl = ""; + + // Model Settings + @Builder.Default + private String llmModel = "gpt-4o-mini"; + + @Builder.Default + private String embeddingModel = "text-embedding-3-large"; + + @Builder.Default + private int embeddingDimension = 3072; + + // Milvus Settings + @Builder.Default + private String milvusUri = "./vector_graph_rag.db"; + + @Builder.Default + private String milvusToken = ""; + + @Builder.Default + private String milvusDb = ""; + + // Milvus Index Settings + @Builder.Default + private String milvusIndexType = "AUTOINDEX"; + + @Builder.Default + private String milvusMetricType = "IP"; + + private Map milvusIndexParams; + + @Builder.Default + private String milvusConsistencyLevel = "Bounded"; + + // Collection prefix + @Builder.Default + private String collectionPrefix = ""; + + // Collection Names + @Builder.Default + private String entityCollection = "vgrag_entities"; + + @Builder.Default + private String relationCollection = "vgrag_relations"; + + @Builder.Default + private String passageCollection = "vgrag_passages"; + + // Retrieval Settings + @Builder.Default + private int entityTopK = 20; + + @Builder.Default + private int relationTopK = 20; + + @Builder.Default + private float entitySimilarityThreshold = 0.9f; + + @Builder.Default + private float relationSimilarityThreshold = -1.0f; + + @Builder.Default + private int expansionDegree = 1; + + @Builder.Default + private int relationNumberThreshold = 1000; + + @Builder.Default + private int finalTopK = 3; + + // LLM Settings + @Builder.Default + private double llmTemperature = 0.0; + + @Builder.Default + private int llmMaxRetries = 3; + + @Builder.Default + private boolean useLlmCache = true; + + // Processing Settings + @Builder.Default + private int batchSize = 32; + + public boolean hasCollectionPrefix() { + return collectionPrefix != null && !collectionPrefix.isEmpty(); + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/Graph.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/Graph.java new file mode 100644 index 0000000..477b63c --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/Graph.java @@ -0,0 +1,258 @@ +package com.zjkl.vectorgraphrag.graph; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.model.*; +import com.zjkl.vectorgraphrag.storage.EmbeddingClient; +import com.zjkl.vectorgraphrag.storage.MilvusStore; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.zjkl.vectorgraphrag.graph.GraphBuilder.normalizePhrase; + +/** + * User-facing graph operations interface. + * Encapsulates MilvusStore with CRUD operations and automatic entity/relation linking. + */ +@Slf4j +public class Graph { + + private final VectorGraphRagSettings settings; + private final EmbeddingClient embeddingClient; + private final MilvusStore store; + + private final Map entityNameToId = new HashMap<>(); + private final Map relationTextToId = new HashMap<>(); + + public Graph(VectorGraphRagSettings settings, MilvusStore store, EmbeddingClient embeddingClient) { + this.settings = settings; + this.store = store; + this.embeddingClient = embeddingClient; + } + + // ==================== Passage CRUD ==================== + + public String createPassage(String text) { + return createPassage(text, null, null); + } + + public String createPassage(String text, String id) { + return createPassage(text, id, null); + } + + public String createPassage(String text, String id, List triplets) { + String passageId = id != null ? id : UUID.randomUUID().toString(); + List embedding = embeddingClient.embed(text); + + List entityIds = new ArrayList<>(); + List relationIds = new ArrayList<>(); + + if (triplets != null) { + for (Triplet triplet : triplets) { + String relationId = createRelation(triplet.getSubject(), triplet.getPredicate(), + triplet.getObject(), null, List.of(passageId)); + relationIds.add(relationId); + + String subjectId = entityNameToId.get(normalizePhrase(triplet.getSubject())); + String objectId = entityNameToId.get(normalizePhrase(triplet.getObject())); + if (subjectId != null && !entityIds.contains(subjectId)) entityIds.add(subjectId); + if (objectId != null && !entityIds.contains(objectId)) entityIds.add(objectId); + } + } + + Map metadata = new HashMap<>(); + if (!entityIds.isEmpty()) metadata.put("entity_ids", entityIds); + if (!relationIds.isEmpty()) metadata.put("relation_ids", relationIds); + + List> metadatas = metadata.isEmpty() ? null : List.of(metadata); + store.insertPassages(List.of(text), List.of(passageId), List.of(embedding), metadatas, false); + + return passageId; + } + + public Passage getPassage(String passageId) { + List> results = store.getPassagesByIds(List.of(passageId)); + if (results.isEmpty()) return null; + + Map data = results.get(0); + return Passage.builder() + .id(safeGet(data, "id")) + .text(safeGet(data, "text")) + .entityIds(safeGetList(data, "entity_ids")) + .relationIds(safeGetList(data, "relation_ids")) + .build(); + } + + public List searchPassages(String query, int topK) { + List queryEmbedding = embeddingClient.embed(query); + List> results = store.searchPassages(queryEmbedding, topK, null); + + return results.stream().map(r -> { + @SuppressWarnings("unchecked") + Map entity = (Map) r.get("entity"); + return Passage.builder() + .id(safeGet(entity, "id")) + .text(safeGet(entity, "text")) + .entityIds(safeGetList(entity, "entity_ids")) + .relationIds(safeGetList(entity, "relation_ids")) + .build(); + }).collect(Collectors.toList()); + } + + public boolean updatePassage(String passageId, String text, List entityIds, List relationIds) { + return store.upsertPassage(passageId, text, null, entityIds, relationIds); + } + + public boolean deletePassage(String passageId) { + List> passages = store.getPassagesByIds(List.of(passageId)); + if (passages.isEmpty()) return false; + + Map data = passages.get(0); + List entityIds = safeGetList(data, "entity_ids"); + List relationIds = safeGetList(data, "relation_ids"); + + // Cascade: remove passage reference from entities + for (String eid : entityIds) { + List> entities = store.getEntitiesByIds(List.of(eid)); + if (!entities.isEmpty()) { + List pids = safeGetList(entities.get(0), "passage_ids"); + pids.remove(passageId); + store.upsertEntity(eid, null, null, null, pids); + } + } + + // Cascade: remove passage reference from relations + for (String rid : relationIds) { + List> rels = store.getRelationsByIds(List.of(rid)); + if (!rels.isEmpty()) { + List pids = safeGetList(rels.get(0), "passage_ids"); + pids.remove(passageId); + store.upsertRelation(rid, null, null, null, pids, null, null, null); + } + } + + return store.deletePassage(passageId); + } + + // ==================== Private: Entity & Relation CRUD ==================== + + private String createRelation(String subject, String predicate, String object, + String id, List passageIds) { + String normSubject = normalizePhrase(subject); + String normPredicate = normalizePhrase(predicate); + String normObject = normalizePhrase(object); + String relationText = normSubject + " " + normPredicate + " " + normObject; + + if (relationTextToId.containsKey(relationText)) { + String existingId = relationTextToId.get(relationText); + if (passageIds != null && !passageIds.isEmpty()) { + List> existing = store.getRelationsByIds(List.of(existingId)); + if (!existing.isEmpty()) { + List currentPids = safeGetList(existing.get(0), "passage_ids"); + Set merged = new LinkedHashSet<>(currentPids); + merged.addAll(passageIds); + store.upsertRelation(existingId, null, null, null, new ArrayList<>(merged), + null, null, null); + } + } + return existingId; + } + + String relationId = id != null ? id : UUID.randomUUID().toString(); + + String subjectId = createEntity(subject, List.of(relationId), passageIds); + String objectId = createEntity(object, List.of(relationId), passageIds); + + List embedding = embeddingClient.embed(relationText); + + Map metadata = new HashMap<>(); + metadata.put("entity_ids", List.of(subjectId, objectId)); + metadata.put("subject", normSubject); + metadata.put("predicate", normPredicate); + metadata.put("object", normObject); + if (passageIds != null && !passageIds.isEmpty()) { + metadata.put("passage_ids", passageIds); + } + + store.insertRelations(List.of(relationText), List.of(relationId), + List.of(embedding), List.of(metadata), false); + + relationTextToId.put(relationText, relationId); + return relationId; + } + + private String createEntity(String name, List relationIds, List passageIds) { + String normalized = normalizePhrase(name); + if (entityNameToId.containsKey(normalized)) { + String existingId = entityNameToId.get(normalized); + if (relationIds != null || passageIds != null) { + List> existing = store.getEntitiesByIds(List.of(existingId)); + if (!existing.isEmpty()) { + List currentRels = safeGetList(existing.get(0), "relation_ids"); + List currentPids = safeGetList(existing.get(0), "passage_ids"); + Set mergedRels = new LinkedHashSet<>(currentRels); + if (relationIds != null) mergedRels.addAll(relationIds); + Set mergedPids = new LinkedHashSet<>(currentPids); + if (passageIds != null) mergedPids.addAll(passageIds); + store.upsertEntity(existingId, null, null, + new ArrayList<>(mergedRels), new ArrayList<>(mergedPids)); + } + } + return existingId; + } + + String entityId = UUID.randomUUID().toString(); + List embedding = embeddingClient.embed(normalized); + + Map metadata = new HashMap<>(); + if (relationIds != null && !relationIds.isEmpty()) metadata.put("relation_ids", relationIds); + if (passageIds != null && !passageIds.isEmpty()) metadata.put("passage_ids", passageIds); + + List> metadatas = metadata.isEmpty() ? null : List.of(metadata); + store.insertEntities(List.of(normalized), List.of(entityId), + List.of(embedding), metadatas, false); + + entityNameToId.put(normalized, entityId); + return entityId; + } + + // ==================== SubGraph Creation ==================== + + public SubGraph createSubGraph() { + return new SubGraph(store); + } + + // ==================== Collection Management ==================== + + public void createCollections(boolean dropExisting) { + store.createCollections(dropExisting); + } + + public void dropCollections() { + store.dropCollections(); + entityNameToId.clear(); + relationTextToId.clear(); + } + + public void reset() { + dropCollections(); + store.createCollections(true); + } + + // ==================== Helpers ==================== + + @SuppressWarnings("unchecked") + private List safeGetList(Map map, String key) { + Object val = map.get(key); + if (val instanceof List) { + return ((List) val).stream().map(Object::toString).collect(Collectors.toList()); + } + return new ArrayList<>(); + } + + private String safeGet(Map map, String key) { + Object val = map.get(key); + return val != null ? val.toString() : ""; + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphBuilder.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphBuilder.java new file mode 100644 index 0000000..d2c72e0 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphBuilder.java @@ -0,0 +1,200 @@ +package com.zjkl.vectorgraphrag.graph; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.model.*; +import lombok.Getter; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Builds in-memory graph structures from documents with extracted triplets. + * Manages entity-relation-passage adjacency mappings. + */ +public class GraphBuilder { + + private final VectorGraphRagSettings settings; + + // id -> text + @Getter + private final Map entities = new LinkedHashMap<>(); + @Getter + private final Map relations = new LinkedHashMap<>(); + @Getter + private final Map passages = new LinkedHashMap<>(); + + // ordered IDs + @Getter + private final List entityIds = new ArrayList<>(); + @Getter + private final List relationIds = new ArrayList<>(); + @Getter + private final List passageIds = new ArrayList<>(); + + // deduplication + private final Map entityNameToId = new HashMap<>(); + private final Map relationTextToId = new HashMap<>(); + + // triplet storage + @Getter + private final Map relationIdToTriplet = new HashMap<>(); + + // adjacency + @Getter + private final Map> entityToRelationIds = new HashMap<>(); + @Getter + private final Map> entityToPassageIds = new HashMap<>(); + @Getter + private final Map> relationToPassageIds = new HashMap<>(); + @Getter + private final Map> relationToEntityIds = new HashMap<>(); + @Getter + private final Map> passageToEntityIds = new HashMap<>(); + @Getter + private final Map> passageToRelationIds = new HashMap<>(); + + public GraphBuilder(VectorGraphRagSettings settings) { + this.settings = settings; + } + + public void clear() { + entities.clear(); + relations.clear(); + passages.clear(); + entityIds.clear(); + relationIds.clear(); + passageIds.clear(); + entityNameToId.clear(); + relationTextToId.clear(); + relationIdToTriplet.clear(); + entityToRelationIds.clear(); + entityToPassageIds.clear(); + relationToPassageIds.clear(); + relationToEntityIds.clear(); + passageToEntityIds.clear(); + passageToRelationIds.clear(); + } + + public ExtractionResult buildFromDocuments(List documents) { + clear(); + + for (Document doc : documents) { + String passageId = doc.getId() != null ? doc.getId() : UUID.randomUUID().toString(); + passages.put(passageId, doc.getText()); + passageIds.add(passageId); + if (doc.getId() == null) doc.setId(passageId); + + // Process triplets + List triplets = doc.getTriplets(); + if (triplets == null) triplets = List.of(); + + // Also check metadata for raw triplets + Object rawTriplets = doc.getMetadata().get("triplets"); + if (rawTriplets instanceof List) { + for (Object raw : (List) rawTriplets) { + if (raw instanceof List && ((List) raw).size() >= 3) { + List parts = (List) raw; + Triplet t = new Triplet( + String.valueOf(parts.get(0)), + String.valueOf(parts.get(1)), + String.valueOf(parts.get(2)) + ); + addRelation(t, passageId); + } else if (raw instanceof Triplet) { + addRelation((Triplet) raw, passageId); + } + } + } else { + for (Triplet t : triplets) { + addRelation(t, passageId); + } + } + } + + // Build result + List entityList = entityIds.stream() + .map(eid -> Entity.builder().id(eid).name(entities.get(eid)).build()) + .collect(Collectors.toList()); + + List relationList = relationIds.stream() + .map(rid -> Relation.builder() + .id(rid) + .text(relations.get(rid)) + .triplet(relationIdToTriplet.get(rid)) + .sourcePassageIds(new ArrayList<>(relationToPassageIds.getOrDefault(rid, List.of()))) + .build()) + .collect(Collectors.toList()); + + return ExtractionResult.builder() + .documents(documents.stream().map(Document::getText).collect(Collectors.toList())) + .entities(entityList) + .relations(relationList) + .entityToRelationIds(new HashMap<>(entityToRelationIds)) + .relationToPassageIds(new HashMap<>(relationToPassageIds)) + .build(); + } + + private String addRelation(Triplet triplet, String passageId) { + String subject = normalizePhrase(triplet.getSubject()); + String predicate = normalizePhrase(triplet.getPredicate()); + String obj = normalizePhrase(triplet.getObject()); + String relationText = subject + " " + predicate + " " + obj; + + String relationId = relationTextToId.get(relationText); + if (relationId == null) { + relationId = UUID.randomUUID().toString(); + relations.put(relationId, relationText); + relationIds.add(relationId); + relationTextToId.put(relationText, relationId); + relationIdToTriplet.put(relationId, triplet); + + String subjectId = addEntity(triplet.getSubject(), passageId); + String objectId = addEntity(triplet.getObject(), passageId); + + entityToRelationIds.computeIfAbsent(subjectId, k -> new ArrayList<>()).add(relationId); + entityToRelationIds.computeIfAbsent(objectId, k -> new ArrayList<>()).add(relationId); + relationToEntityIds.put(relationId, List.of(subjectId, objectId)); + } + + // Link relation to passage + relationToPassageIds.computeIfAbsent(relationId, k -> new ArrayList<>()).add(passageId); + passageToRelationIds.computeIfAbsent(passageId, k -> new ArrayList<>()).add(relationId); + + return relationId; + } + + private String addEntity(String entityName, String passageId) { + String normalized = normalizePhrase(entityName); + String entityId = entityNameToId.get(normalized); + if (entityId == null) { + entityId = UUID.randomUUID().toString(); + entities.put(entityId, normalized); + entityIds.add(entityId); + entityNameToId.put(normalized, entityId); + } + + // Link entity to passage + entityToPassageIds.computeIfAbsent(entityId, k -> new ArrayList<>()).add(passageId); + passageToEntityIds.computeIfAbsent(passageId, k -> new ArrayList<>()).add(entityId); + + return entityId; + } + + public static String normalizePhrase(String phrase) { + if (phrase == null) return ""; + // Replace all non-alphanumeric chars with space, lowercase, trim + return phrase.replaceAll("[^A-Za-z0-9 ]", " ").toLowerCase().trim(); + } + + public List getEntityTexts() { + return entityIds.stream().map(entities::get).collect(Collectors.toList()); + } + + public List getRelationTexts() { + return relationIds.stream().map(relations::get).collect(Collectors.toList()); + } + + public List getPassageTexts() { + return passageIds.stream().map(passages::get).collect(Collectors.toList()); + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphRetriever.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphRetriever.java new file mode 100644 index 0000000..c2ef47a --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/GraphRetriever.java @@ -0,0 +1,237 @@ +package com.zjkl.vectorgraphrag.graph; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.llm.EntityExtractor; +import com.zjkl.vectorgraphrag.model.RetrievalResult; +import com.zjkl.vectorgraphrag.storage.EmbeddingClient; +import com.zjkl.vectorgraphrag.storage.MilvusStore; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Graph-based retriever using multi-way vector search. + * Performs entity and relation retrieval, then expands the subgraph + * with lazy loading from Milvus. + */ +@Slf4j +public class GraphRetriever { + + private final VectorGraphRagSettings settings; + private final MilvusStore store; + private final EmbeddingClient embeddingClient; + private final EntityExtractor entityExtractor; + + public GraphRetriever(VectorGraphRagSettings settings, MilvusStore store, + EmbeddingClient embeddingClient, EntityExtractor entityExtractor) { + this.settings = settings; + this.store = store; + this.embeddingClient = embeddingClient; + this.entityExtractor = entityExtractor; + } + + public RetrievalResult retrieve(String query) { + return retrieve(query, null, null, null, null, null, null); + } + + public RetrievalResult retrieve(String query, + Integer entityTopK, + Integer relationTopK, + Float entitySimilarityThreshold, + Float relationSimilarityThreshold, + Integer expansionDegree, + String filter) { + Set allowedPassageIds = getAllowedPassageIds(filter); + + // Extract query entities + List queryEntities = entityExtractor.extract(query); + + // Retrieve entities + List entityIds = new ArrayList<>(); + List entityTexts = new ArrayList<>(); + List entityScores = new ArrayList<>(); + + if (!queryEntities.isEmpty()) { + List> queryEmbeddings = embeddingClient.embedBatch(queryEntities); + int eTopK = entityTopK != null ? entityTopK : settings.getEntityTopK(); + float eThreshold = entitySimilarityThreshold != null ? entitySimilarityThreshold + : settings.getEntitySimilarityThreshold(); + + List> searchResults = store.searchEntities(queryEmbeddings, eTopK); + Set seenIds = new LinkedHashSet<>(); + + for (Map result : searchResults) { + double distance = (double) result.get("distance"); + if (distance <= eThreshold) continue; + + @SuppressWarnings("unchecked") + Map entity = (Map) result.get("entity"); + String eid = entity.get("id").toString(); + if (seenIds.add(eid)) { + entityIds.add(eid); + entityTexts.add(entity.get("text").toString()); + entityScores.add((float) distance); + } + } + } + + // Retrieve relations + int rTopK = relationTopK != null ? relationTopK : settings.getRelationTopK(); + float rThreshold = relationSimilarityThreshold != null ? relationSimilarityThreshold + : settings.getRelationSimilarityThreshold(); + + List queryEmbedding = embeddingClient.embed(query); + List> relationResults = store.searchRelations(queryEmbedding, rTopK); + + List relationIds = new ArrayList<>(); + List relationTexts = new ArrayList<>(); + List relationScores = new ArrayList<>(); + + for (Map result : relationResults) { + double distance = (double) result.get("distance"); + if (distance <= rThreshold) continue; + + @SuppressWarnings("unchecked") + Map entity = (Map) result.get("entity"); + String rid = entity.get("id").toString(); + relationIds.add(rid); + relationTexts.add(entity.get("text").toString()); + relationScores.add((float) distance); + } + + // Filter relations by allowed passage IDs + if (allowedPassageIds != null) { + List filteredIds = filterRelationsByPassageIds(relationIds, allowedPassageIds); + // Rebuild parallel lists + Set allowed = new HashSet<>(filteredIds); + List keptIds = new ArrayList<>(); + List keptTexts = new ArrayList<>(); + List keptScores = new ArrayList<>(); + for (int i = 0; i < relationIds.size(); i++) { + if (allowed.contains(relationIds.get(i))) { + keptIds.add(relationIds.get(i)); + keptTexts.add(relationTexts.get(i)); + keptScores.add(relationScores.get(i)); + } + } + relationIds = keptIds; + relationTexts = keptTexts; + relationScores = keptScores; + } + + // Expand subgraph + SubGraph subgraph = expandSubGraph(entityIds, relationIds, expansionDegree); + + // Apply eviction + int threshold = settings.getRelationNumberThreshold(); + List filteredExpandedIds = filterRelationsByPassageIds( + new ArrayList<>(subgraph.getRelationIds()), allowedPassageIds); + List expandedIds = new ArrayList<>(); + List expandedTexts = new ArrayList<>(); + boolean evictionOccurred = false; + int evictionBefore = filteredExpandedIds.size(); + + if (!filteredExpandedIds.isEmpty()) { + if (filteredExpandedIds.size() <= threshold) { + // No eviction needed + expandedIds = filteredExpandedIds; + expandedTexts = filteredExpandedIds.stream() + .map(rid -> { + SubGraphRelation rel = null; + for (SubGraphRelation r : subgraph.getRelations()) { + if (r.getId().equals(rid)) { rel = r; break; } + } + return rel != null ? rel.getText() : ""; + }) + .collect(Collectors.toList()); + } else { + // Eviction: use vector search to filter + log.info("Use Eviction Strategy. ({} -> {})", evictionBefore, threshold); + List qEmbed = embeddingClient.embed(query); + String idsStr = filteredExpandedIds.stream() + .map(id -> "\"" + id + "\"") + .collect(Collectors.joining(", ")); + String filterExpr = "id in [" + idsStr + "]"; + + List> searchRes = store.searchRelationsWithFilter(qEmbed, threshold, filterExpr); + evictionOccurred = true; + for (Map r : searchRes) { + expandedIds.add(r.get("id").toString()); + expandedTexts.add(r.get("text") != null ? r.get("text").toString() : ""); + } + } + } + + return RetrievalResult.builder() + .entityIds(entityIds) + .entityTexts(entityTexts) + .entityScores(entityScores) + .relationIds(relationIds) + .relationTexts(relationTexts) + .relationScores(relationScores) + .subgraph(subgraph) + .expandedRelationIds(expandedIds) + .expandedRelationTexts(expandedTexts) + .query(query) + .queryEntities(queryEntities) + .evictionOccurred(evictionOccurred) + .evictionBeforeCount(evictionBefore) + .evictionAfterCount(expandedIds.size()) + .build(); + } + + public List retrievePassagesNaive(String query, int topK, String filter) { + List queryEmbedding = embeddingClient.embed(query); + List> results = store.searchPassages(queryEmbedding, topK, filter); + return results.stream() + .map(r -> { + @SuppressWarnings("unchecked") + Map entity = (Map) r.get("entity"); + return entity.get("text").toString(); + }) + .collect(Collectors.toList()); + } + + private SubGraph expandSubGraph(List entityIds, List relationIds, Integer degree) { + int deg = degree != null ? degree : settings.getExpansionDegree(); + SubGraph subgraph = new SubGraph(store); + subgraph.addEntities(entityIds); + subgraph.addRelations(relationIds); + subgraph.expand(deg); + return subgraph; + } + + private Set getAllowedPassageIds(String filter) { + if (filter == null || filter.trim().isEmpty()) return null; + return new HashSet<>(store.queryPassageIds(filter)); + } + + private List filterRelationsByPassageIds(List relationIds, Set allowedPassageIds) { + if (allowedPassageIds == null) return relationIds; + if (relationIds == null || relationIds.isEmpty()) return List.of(); + + List> relationData = store.getRelationsByIds(relationIds); + Set allowed = new HashSet<>(); + for (Map r : relationData) { + List pids = safeGetList(r, "passage_ids"); + for (String pid : pids) { + if (allowedPassageIds.contains(pid)) { + allowed.add(r.get("id").toString()); + break; + } + } + } + + return relationIds.stream().filter(allowed::contains).collect(Collectors.toList()); + } + + @SuppressWarnings("unchecked") + private List safeGetList(Map map, String key) { + Object val = map.get(key); + if (val instanceof List) { + return ((List) val).stream().map(Object::toString).collect(Collectors.toList()); + } + return List.of(); + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraph.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraph.java new file mode 100644 index 0000000..85f0ab0 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraph.java @@ -0,0 +1,298 @@ +package com.zjkl.vectorgraphrag.graph; + +import com.zjkl.vectorgraphrag.storage.MilvusStore; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Lazy-loading subgraph for graph expansion. + * Starts from seed entities/relations and expands by fetching + * neighbor data on-demand from Milvus storage. + */ +@Slf4j +public class SubGraph { + + private final MilvusStore store; + + private final Set entityIds = new LinkedHashSet<>(); + private final Set relationIds = new LinkedHashSet<>(); + private final Set passageIds = new LinkedHashSet<>(); + + private final Map entityMap = new HashMap<>(); + private final Map relationMap = new HashMap<>(); + private final Map passageMap = new HashMap<>(); + + @Getter + private final List> expansionHistory = new ArrayList<>(); + + public SubGraph(MilvusStore store) { + this.store = store; + } + + // ==================== Add Initial Nodes ==================== + + public SubGraph addEntities(List ids) { + Set newIds = new LinkedHashSet<>(ids); + newIds.removeAll(entityIds); + if (!newIds.isEmpty()) { + entityIds.addAll(newIds); + fetchEntities(new ArrayList<>(newIds)); + + if (expansionHistory.isEmpty()) { + Map step = new LinkedHashMap<>(); + step.put("step", 0); + step.put("operation", "init"); + step.put("addedEntityIds", new ArrayList<>(newIds)); + step.put("addedRelationIds", List.of()); + expansionHistory.add(step); + } else { + @SuppressWarnings("unchecked") + List added = (List) expansionHistory.get(0).get("addedEntityIds"); + added.addAll(newIds); + } + } + return this; + } + + public SubGraph addRelations(List ids) { + Set newIds = new LinkedHashSet<>(ids); + newIds.removeAll(relationIds); + if (!newIds.isEmpty()) { + relationIds.addAll(newIds); + fetchRelations(new ArrayList<>(newIds)); + + if (expansionHistory.isEmpty()) { + Map step = new LinkedHashMap<>(); + step.put("step", 0); + step.put("operation", "init"); + step.put("addedEntityIds", List.of()); + step.put("addedRelationIds", new ArrayList<>(newIds)); + expansionHistory.add(step); + } else { + @SuppressWarnings("unchecked") + List added = (List) expansionHistory.get(0).get("addedRelationIds"); + added.addAll(newIds); + } + } + return this; + } + + // ==================== Expansion ==================== + + public SubGraph expand(int degree) { + // Step 0: From initial entities -> relations, merge with initial relations + Set initNewRelations = new LinkedHashSet<>(); + for (String eid : entityIds) { + SubGraphEntity entity = entityMap.get(eid); + if (entity != null) { + for (String rid : entity.getRelationIds()) { + if (!relationIds.contains(rid)) { + initNewRelations.add(rid); + } + } + } + } + + if (!initNewRelations.isEmpty()) { + fetchRelations(new ArrayList<>(initNewRelations)); + relationIds.addAll(initNewRelations); + } + + Map initStep = new LinkedHashMap<>(); + initStep.put("step", expansionHistory.size()); + initStep.put("operation", "init_merge"); + initStep.put("newRelationIds", new ArrayList<>(initNewRelations)); + initStep.put("totalEntities", entityIds.size()); + initStep.put("totalRelations", relationIds.size()); + expansionHistory.add(initStep); + + // For each degree: relations -> entities -> relations + for (int step = 0; step < degree; step++) { + Set stepNewEntities = new LinkedHashSet<>(); + Set stepNewRelations = new LinkedHashSet<>(); + + // From current relations -> entities + for (String rid : relationIds) { + SubGraphRelation relation = relationMap.get(rid); + if (relation != null) { + for (String eid : relation.getEntityIds()) { + if (!entityIds.contains(eid)) { + stepNewEntities.add(eid); + } + } + } + } + + // Fetch new entities + if (!stepNewEntities.isEmpty()) { + fetchEntities(new ArrayList<>(stepNewEntities)); + entityIds.addAll(stepNewEntities); + } + + // From new entities -> relations + for (String eid : stepNewEntities) { + SubGraphEntity entity = entityMap.get(eid); + if (entity != null) { + for (String rid : entity.getRelationIds()) { + if (!relationIds.contains(rid)) { + stepNewRelations.add(rid); + } + } + } + } + + // Fetch new relations + if (!stepNewRelations.isEmpty()) { + fetchRelations(new ArrayList<>(stepNewRelations)); + relationIds.addAll(stepNewRelations); + } + + Map stepRecord = new LinkedHashMap<>(); + stepRecord.put("step", expansionHistory.size()); + stepRecord.put("operation", "expand_degree_" + (step + 1)); + stepRecord.put("newEntityIds", new ArrayList<>(stepNewEntities)); + stepRecord.put("newRelationIds", new ArrayList<>(stepNewRelations)); + stepRecord.put("totalEntities", entityIds.size()); + stepRecord.put("totalRelations", relationIds.size()); + expansionHistory.add(stepRecord); + } + + // Collect passages from all relations + for (String rid : relationIds) { + SubGraphRelation relation = relationMap.get(rid); + if (relation != null) { + passageIds.addAll(relation.getPassageIds()); + } + } + + // Fetch passages + if (!passageIds.isEmpty()) { + fetchPassages(new ArrayList<>(passageIds)); + } + + return this; + } + + // ==================== Data Fetching ==================== + + private void fetchEntities(List ids) { + List toFetch = ids.stream() + .filter(id -> !entityMap.containsKey(id)) + .collect(Collectors.toList()); + if (toFetch.isEmpty()) return; + + List> results = store.getEntitiesByIds(toFetch); + for (Map r : results) { + SubGraphEntity entity = SubGraphEntity.builder() + .id(safeGet(r, "id")) + .name(safeGet(r, "text")) + .relationIds(safeGetList(r, "relation_ids")) + .passageIds(safeGetList(r, "passage_ids")) + .build(); + entityMap.put(entity.getId(), entity); + } + } + + private void fetchRelations(List ids) { + List toFetch = ids.stream() + .filter(id -> !relationMap.containsKey(id)) + .collect(Collectors.toList()); + if (toFetch.isEmpty()) return; + + List> results = store.getRelationsByIds(toFetch); + for (Map r : results) { + String text = safeGet(r, "text"); + String subject = r.getOrDefault("subject", "").toString(); + String predicate = r.getOrDefault("predicate", "").toString(); + String obj = r.getOrDefault("object", "").toString(); + + // Fallback parsing + if (subject.isEmpty() && predicate.isEmpty() && obj.isEmpty()) { + String[] parts = text.split(" ", 3); + subject = parts.length > 0 ? parts[0] : ""; + predicate = parts.length > 1 ? parts[1] : ""; + obj = parts.length > 2 ? parts[2] : ""; + } + + SubGraphRelation relation = SubGraphRelation.builder() + .id(safeGet(r, "id")) + .text(text) + .subject(subject) + .predicate(predicate) + .object(obj) + .entityIds(safeGetList(r, "entity_ids")) + .passageIds(safeGetList(r, "passage_ids")) + .build(); + relationMap.put(relation.getId(), relation); + } + } + + private void fetchPassages(List ids) { + List toFetch = ids.stream() + .filter(id -> !passageMap.containsKey(id)) + .collect(Collectors.toList()); + if (toFetch.isEmpty()) return; + + List> results = store.getPassagesByIds(toFetch); + for (Map r : results) { + SubGraphPassage passage = SubGraphPassage.builder() + .id(safeGet(r, "id")) + .text(safeGet(r, "text")) + .entityIds(safeGetList(r, "entity_ids")) + .relationIds(safeGetList(r, "relation_ids")) + .build(); + passageMap.put(passage.getId(), passage); + } + } + + // ==================== Accessors ==================== + + public Set getEntityIds() { return Collections.unmodifiableSet(entityIds); } + public Set getRelationIds() { return Collections.unmodifiableSet(relationIds); } + public Set getPassageIds() { return Collections.unmodifiableSet(passageIds); } + + public List getEntities() { + return entityIds.stream().map(entityMap::get).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public List getRelations() { + return relationIds.stream().map(relationMap::get).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public List getPassages() { + return passageIds.stream().map(passageMap::get).filter(Objects::nonNull).collect(Collectors.toList()); + } + + public List getEntityNames() { + return getEntities().stream().map(SubGraphEntity::getName).collect(Collectors.toList()); + } + + public List getRelationTexts() { + return getRelations().stream().map(SubGraphRelation::getText).collect(Collectors.toList()); + } + + public List getPassageTexts() { + return getPassages().stream().map(SubGraphPassage::getText).collect(Collectors.toList()); + } + + // ==================== Helpers ==================== + + @SuppressWarnings("unchecked") + private List safeGetList(Map map, String key) { + Object val = map.get(key); + if (val instanceof List) { + return ((List) val).stream() + .map(Object::toString) + .collect(Collectors.toList()); + } + return List.of(); + } + + private String safeGet(Map map, String key) { + Object val = map.get(key); + return val != null ? val.toString() : ""; + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphEntity.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphEntity.java new file mode 100644 index 0000000..b4f7091 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphEntity.java @@ -0,0 +1,22 @@ +package com.zjkl.vectorgraphrag.graph; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SubGraphEntity { + private String id; + private String name; + @Builder.Default + private List relationIds = new ArrayList<>(); + @Builder.Default + private List passageIds = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphPassage.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphPassage.java new file mode 100644 index 0000000..7b0fe08 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphPassage.java @@ -0,0 +1,22 @@ +package com.zjkl.vectorgraphrag.graph; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SubGraphPassage { + private String id; + private String text; + @Builder.Default + private List entityIds = new ArrayList<>(); + @Builder.Default + private List relationIds = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphRelation.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphRelation.java new file mode 100644 index 0000000..5dfd76c --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/graph/SubGraphRelation.java @@ -0,0 +1,25 @@ +package com.zjkl.vectorgraphrag.graph; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SubGraphRelation { + private String id; + private String text; + private String subject; + private String predicate; + private String object; + @Builder.Default + private List entityIds = new ArrayList<>(); + @Builder.Default + private List passageIds = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/AnswerGenerator.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/AnswerGenerator.java new file mode 100644 index 0000000..9f5c5a9 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/AnswerGenerator.java @@ -0,0 +1,45 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * Generates answers using retrieved passage context via LLM. + */ +@Slf4j +public class AnswerGenerator { + + private static final String ANSWER_PROMPT = + "Use the following pieces of retrieved context to answer the question. " + + "If there is not enough information in the retrieved context to answer the question, " + + "just say that you don't know.\n\n" + + "Question: {question}\n\n" + + "Context: {context}\n\n" + + "Answer:"; + + private final OpenAiClient openAiClient; + private final VectorGraphRagSettings settings; + + public AnswerGenerator(VectorGraphRagSettings settings, OpenAiClient openAiClient) { + this.settings = settings; + this.openAiClient = openAiClient; + } + + public String generate(String question, List passages) { + String context = String.join("\n\n", passages); + String prompt = ANSWER_PROMPT + .replace("{question}", question) + .replace("{context}", context); + + try { + return openAiClient.chatWithMessages(List.of( + java.util.Map.of("role", "user", "content", prompt) + )); + } catch (Exception e) { + log.warn("Answer generation failed: {}", e.getMessage()); + return "I don't know."; + } + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/EntityExtractor.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/EntityExtractor.java new file mode 100644 index 0000000..6af1989 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/EntityExtractor.java @@ -0,0 +1,82 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.zjkl.vectorgraphrag.graph.GraphBuilder.normalizePhrase; + +/** + * Extracts named entities from text for query processing (NER). + * Used during query time to identify entities in the user's question. + */ +@Slf4j +public class EntityExtractor { + + private static final String SYSTEM_PROMPT = + "You're a very effective entity extraction system."; + + private static final String ONE_SHOT_INPUT = + "Please extract all named entities that are important for solving the questions below.\n" + + "Place the named entities in json format.\n\n" + + "Question: Which magazine was started first Arthur's Magazine or First for Women?"; + + private static final String ONE_SHOT_OUTPUT = + "{\"named_entities\": [\"First for Women\", \"Arthur's Magazine\"]}"; + + private static final String TEMPLATE = "\nQuestion: {}\n"; + + private final OpenAiClient openAiClient; + private final Gson gson; + + public EntityExtractor(VectorGraphRagSettings settings, OpenAiClient openAiClient) { + this.openAiClient = openAiClient; + this.gson = new Gson(); + } + + public List extract(String question) { + if (question == null || question.trim().isEmpty()) return List.of(); + + try { + List> examples = List.of( + Map.of("user", ONE_SHOT_INPUT, "assistant", ONE_SHOT_OUTPUT) + ); + String response = openAiClient.chat(SYSTEM_PROMPT, examples, + TEMPLATE.replace("{}", question)); + + return parseResponse(response); + } catch (Exception e) { + log.warn("Entity extraction failed, returning empty: {}", e.getMessage()); + return List.of(); + } + } + + private List parseResponse(String response) { + try { + JsonObject json = gson.fromJson(response, JsonObject.class); + JsonArray entities = json.getAsJsonArray("named_entities"); + if (entities == null) { + entities = json.getAsJsonArray("entities"); + } + if (entities == null) return List.of(); + + List results = new ArrayList<>(); + for (int i = 0; i < entities.size(); i++) { + String entity = entities.get(i).getAsString(); + if (entity != null && !entity.trim().isEmpty()) { + results.add(normalizePhrase(entity)); + } + } + return results; + } catch (Exception e) { + log.warn("Failed to parse NER response: {}", e.getMessage()); + return List.of(); + } + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMCache.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMCache.java new file mode 100644 index 0000000..386ab6b --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMCache.java @@ -0,0 +1,74 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.concurrent.TimeUnit; + +/** + * LLM response cache. + * Uses Caffeine in-memory cache with file-backed persistence. + * Each model has its own cache namespace. + */ +@Slf4j +public class LLMCache { + + private final Cache cache; + + public LLMCache() { + this(10000, 24, TimeUnit.HOURS); + } + + public LLMCache(int maxSize, long duration, TimeUnit unit) { + this.cache = Caffeine.newBuilder() + .maximumSize(maxSize) + .expireAfterWrite(duration, unit) + .recordStats() + .build(); + } + + public String get(String modelName, String prompt, double temperature) { + String key = buildKey(modelName, prompt, temperature); + String result = cache.getIfPresent(key); + if (result != null) { + log.debug("LLM cache hit for model={}", modelName); + } + return result; + } + + public void set(String modelName, String prompt, String response, double temperature) { + String key = buildKey(modelName, prompt, temperature); + cache.put(key, response); + } + + public void clear() { + cache.invalidateAll(); + } + + public long size() { + return cache.estimatedSize(); + } + + private String buildKey(String modelName, String prompt, double temperature) { + String raw = modelName + "::" + prompt + "::temp=" + temperature; + return md5(raw); + } + + private String md5(String input) { + try { + MessageDigest digest = MessageDigest.getInstance("MD5"); + byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder hex = new StringBuilder(); + for (byte b : hash) { + hex.append(String.format("%02x", b)); + } + return hex.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 not available", e); + } + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMReranker.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMReranker.java new file mode 100644 index 0000000..f5c2e57 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/LLMReranker.java @@ -0,0 +1,180 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * LLM-based reranker for candidate relations. + * Uses few-shot prompting with chain-of-thought to select the most relevant relations. + */ +@Slf4j +public class LLMReranker { + + // 3 few-shot examples for 1-hop, 2-hop, and 3-hop reasoning + private static final String EXAMPLE_1_INPUT = + "I will provide you with a set of relationship descriptions from a knowledge graph. Select exactly 5 relationships most useful for answering this multi-hop question.\n\n" + + "Return JSON with \"thought_process\" and \"useful_relations\" (list of 5 relation lines, most useful first).\n\n" + + "Question:\nWhen did Lothair Ii's mother die?\n\n" + + "Relationship descriptions:\n" + + "[53] bertha married to theobald of arles\n" + + "[54] bertha married to adalbert ii of tuscany\n" + + "[42] lothair ii son of ermengarde of tours\n" + + "[43] lothair ii married to teutberga\n" + + "[41] lothair ii son of emperor lothair i\n" + + "[60] lothair ii husband of waldrada\n" + + "[67] waldrada was mistress of lothair ii\n"; + + private static final String EXAMPLE_1_OUTPUT = + "{\"thought_process\": \"2-hop question: First find Lothair II's mother (relation [42]: Ermengarde of Tours), then find death date. [41] gives father for family context.\", " + + "\"useful_relations\": [\"[42] lothair ii son of ermengarde of tours\", \"[41] lothair ii son of emperor lothair i\", \"[43] lothair ii married to teutberga\", \"[60] lothair ii husband of waldrada\", \"[67] waldrada was mistress of lothair ii\"]}"; + + private static final String EXAMPLE_2_INPUT = + "I will provide you with a set of relationship descriptions from a knowledge graph. Select exactly 5 relationships most useful for answering this multi-hop question.\n\n" + + "Return JSON with \"thought_process\" and \"useful_relations\" (list of 5 relation lines, most useful first).\n\n" + + "Question:\nWhat country is the composer of \"Erta Eterna\" from?\n\n" + + "Relationship descriptions:\n" + + "[12] terra eterna composed by paulo flores\n" + + "[15] paulo flores born in angola\n" + + "[18] paulo flores genre is semba\n" + + "[22] angola located in africa\n" + + "[25] semba originated in angola\n" + + "[30] paulo flores nationality angolan\n"; + + private static final String EXAMPLE_2_OUTPUT = + "{\"thought_process\": \"2-hop question: First find composer of Terra Eterna ([12]: Paulo Flores), then find his country ([15] born in Angola or [30] nationality Angolan).\", " + + "\"useful_relations\": [\"[12] terra eterna composed by paulo flores\", \"[15] paulo flores born in angola\", \"[30] paulo flores nationality angolan\", \"[22] angola located in africa\", \"[25] semba originated in angola\"]}"; + + private static final String EXAMPLE_3_INPUT = + "I will provide you with a set of relationship descriptions from a knowledge graph. Select exactly 5 relationships most useful for answering this multi-hop question.\n\n" + + "Return JSON with \"thought_process\" and \"useful_relations\" (list of 5 relation lines, most useful first).\n\n" + + "Question:\nWho is the director of the film that won the award also won by \"The Hurt Locker\"?\n\n" + + "Relationship descriptions:\n" + + "[5] the hurt locker won academy award best picture\n" + + "[8] the hurt locker directed by kathryn bigelow\n" + + "[12] moonlight won academy award best picture\n" + + "[15] moonlight directed by barry jenkins\n" + + "[20] la la land won golden globe best musical\n" + + "[25] barry jenkins born in miami\n"; + + private static final String EXAMPLE_3_OUTPUT = + "{\"thought_process\": \"3-hop question: (1) Find award won by The Hurt Locker ([5]: Academy Award Best Picture), (2) Find another film with same award ([12]: Moonlight), (3) Find director ([15]: Barry Jenkins).\", " + + "\"useful_relations\": [\"[5] the hurt locker won academy award best picture\", \"[12] moonlight won academy award best picture\", \"[15] moonlight directed by barry jenkins\", \"[8] the hurt locker directed by kathryn bigelow\", \"[25] barry jenkins born in miami\"]}"; + + private final OpenAiClient openAiClient; + private final Gson gson; + private final VectorGraphRagSettings settings; + + public LLMReranker(VectorGraphRagSettings settings, OpenAiClient openAiClient) { + this.settings = settings; + this.openAiClient = openAiClient; + this.gson = new Gson(); + } + + public Map.Entry, List> rerank(String query, + List relationIds, + List relationTexts) { + if (relationIds == null || relationIds.isEmpty()) { + return Map.entry(List.of(), List.of()); + } + + // Format relations + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < relationIds.size(); i++) { + sb.append("[").append(relationIds.get(i)).append("] ") + .append(relationTexts.get(i)).append("\n"); + } + String relationDescriptions = sb.toString(); + + // Build prompt + String userPrompt = "Question:\n" + query + "\n\nRelationship descriptions:\n" + relationDescriptions; + + try { + List> messages = new ArrayList<>(); + messages.add(Map.of("role", "user", "content", EXAMPLE_1_INPUT)); + messages.add(Map.of("role", "assistant", "content", EXAMPLE_1_OUTPUT)); + messages.add(Map.of("role", "user", "content", EXAMPLE_2_INPUT)); + messages.add(Map.of("role", "assistant", "content", EXAMPLE_2_OUTPUT)); + messages.add(Map.of("role", "user", "content", EXAMPLE_3_INPUT)); + messages.add(Map.of("role", "assistant", "content", EXAMPLE_3_OUTPUT)); + messages.add(Map.of("role", "user", "content", userPrompt)); + + String response = openAiClient.chatWithMessages(messages); + return parseResponse(response, new HashSet<>(relationIds), relationIds, relationTexts); + + } catch (Exception e) { + log.warn("Reranking failed, using top relations: {}", e.getMessage()); + int limit = Math.min(settings.getFinalTopK(), relationIds.size()); + return Map.entry( + relationIds.subList(0, limit), + relationTexts.subList(0, limit) + ); + } + } + + private Map.Entry, List> parseResponse(String response, + Set validIds, + List allIds, + List allTexts) { + try { + JsonObject json = gson.fromJson(response, JsonObject.class); + JsonArray usefulRelations = json.getAsJsonArray("useful_relations"); + if (usefulRelations == null) { + return Map.entry(List.of(), List.of()); + } + + // Build id->text lookup + Map idToText = new LinkedHashMap<>(); + for (int i = 0; i < allIds.size(); i++) { + idToText.put(allIds.get(i), allTexts.get(i)); + } + + List selectedIds = new ArrayList<>(); + Set seen = new HashSet<>(); + + for (int i = 0; i < usefulRelations.size(); i++) { + String line = usefulRelations.get(i).getAsString(); + String relId = extractIdFromLine(line); + if (relId == null) continue; + + if (validIds.contains(relId) && seen.add(relId)) { + selectedIds.add(relId); + } else if (!validIds.contains(relId)) { + // Try to correct by text matching + String lineText = line.substring(line.indexOf("]") + 1).trim(); + for (int j = 0; j < allTexts.size(); j++) { + if (allTexts.get(j).trim().equalsIgnoreCase(lineText) + && seen.add(allIds.get(j))) { + selectedIds.add(allIds.get(j)); + break; + } + } + } + } + + List selectedTexts = selectedIds.stream() + .map(id -> idToText.getOrDefault(id, "")) + .collect(Collectors.toList()); + + return Map.entry(selectedIds, selectedTexts); + + } catch (Exception e) { + log.warn("Failed to parse reranker response: {}", e.getMessage()); + return Map.entry(List.of(), List.of()); + } + } + + private String extractIdFromLine(String line) { + int start = line.indexOf("["); + int end = line.indexOf("]"); + if (start >= 0 && end > start) { + return line.substring(start + 1, end).trim(); + } + return null; + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/OpenAiClient.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/OpenAiClient.java new file mode 100644 index 0000000..44cfb1a --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/OpenAiClient.java @@ -0,0 +1,281 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import lombok.extern.slf4j.Slf4j; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * OpenAI API client for chat completions and embeddings. + * Uses manual retry with exponential backoff (Spring @Retryable not used + * because this class is not a Spring-managed bean). + */ +@Slf4j +public class OpenAiClient { + + private final VectorGraphRagSettings settings; + private final HttpClient httpClient; + private final Gson gson; + private final LLMCache cache; + + private static final String DEFAULT_CHAT_URL = "https://api.openai.com/v1/chat/completions"; + private static final String DEFAULT_EMBED_URL = "https://api.openai.com/v1/embeddings"; + + public OpenAiClient(VectorGraphRagSettings settings, LLMCache cache) { + this.settings = settings; + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(60)) + .build(); + this.gson = new Gson(); + this.cache = cache; + } + + /** + * Chat completion with structured output (response_format: json_object). + * Used by extractors and rerankers that need parsed JSON responses. + */ + public String chat(String systemPrompt, List> fewShotExamples, String userPrompt) { + String fullPrompt = systemPrompt + "\n" + userPrompt; + if (cache != null && settings.isUseLlmCache()) { + String cached = cache.get(settings.getLlmModel(), fullPrompt, settings.getLlmTemperature()); + if (cached != null) return cached; + } + + JsonArray messages = new JsonArray(); + messages.add(buildMessage("system", systemPrompt)); + for (Map example : fewShotExamples) { + messages.add(buildMessage("user", example.get("user"))); + messages.add(buildMessage("assistant", example.get("assistant"))); + } + messages.add(buildMessage("user", userPrompt)); + + String response = executeChat(messages, true); + + JsonObject jsonResponse = gson.fromJson(response, JsonObject.class); + String content = jsonResponse.getAsJsonArray("choices") + .get(0).getAsJsonObject() + .get("message").getAsJsonObject() + .get("content").getAsString(); + + if (cache != null && settings.isUseLlmCache()) { + cache.set(settings.getLlmModel(), fullPrompt, content, settings.getLlmTemperature()); + } + + return content; + } + + /** + * Chat completion with free-form messages (no response_format restriction). + * Used by AnswerGenerator and similar free-text generation. + */ + public String chatWithMessages(List> messagesList) { + // Build cache key from the conversation + String fullPrompt = messagesList.stream() + .map(m -> m.get("role") + ": " + m.get("content")) + .collect(Collectors.joining("\n")); + + if (cache != null && settings.isUseLlmCache()) { + String cached = cache.get(settings.getLlmModel(), fullPrompt, settings.getLlmTemperature()); + if (cached != null) return cached; + } + + JsonArray messages = new JsonArray(); + for (Map msg : messagesList) { + messages.add(buildMessage(msg.get("role"), msg.get("content"))); + } + + String response = executeChat(messages, false); + + JsonObject jsonResponse = gson.fromJson(response, JsonObject.class); + String content = jsonResponse.getAsJsonArray("choices") + .get(0).getAsJsonObject() + .get("message").getAsJsonObject() + .get("content").getAsString(); + + if (cache != null && settings.isUseLlmCache()) { + cache.set(settings.getLlmModel(), fullPrompt, content, settings.getLlmTemperature()); + } + + return content; + } + + /** + * Embed a single text string into a vector. + */ + public List embed(String text) { + JsonObject body = new JsonObject(); + body.addProperty("model", settings.getEmbeddingModel()); + body.addProperty("input", text); + + String response = executeHttp(buildEmbedUrl(), body.toString(), settings.getLlmMaxRetries()); + return parseEmbeddingResponse(response, 0); + } + + /** + * Embed multiple texts in a single API call (batch). + * Returns embeddings in the same order as input texts. + */ + public List> embedBatch(List texts) { + if (texts == null || texts.isEmpty()) return List.of(); + + JsonObject body = new JsonObject(); + body.addProperty("model", settings.getEmbeddingModel()); + JsonArray inputs = new JsonArray(); + for (String t : texts) inputs.add(t); + body.add("input", inputs); + + String response = executeHttp(buildEmbedUrl(), body.toString(), settings.getLlmMaxRetries()); + + JsonObject jsonResponse = gson.fromJson(response, JsonObject.class); + JsonArray data = jsonResponse.getAsJsonArray("data"); + + // Index by the "index" field in the response to preserve order + List> results = new ArrayList<>(); + for (int i = 0; i < texts.size(); i++) results.add(null); + + for (int i = 0; i < data.size(); i++) { + JsonObject item = data.get(i).getAsJsonObject(); + int idx = item.get("index").getAsInt(); + JsonArray embedding = item.getAsJsonArray("embedding"); + List vec = new ArrayList<>(); + for (int j = 0; j < embedding.size(); j++) { + vec.add(embedding.get(j).getAsFloat()); + } + results.set(idx, vec); + } + return results; + } + + /** + * Build and execute a chat request. + */ + private String executeChat(JsonArray messages, boolean responseJson) { + JsonObject body = new JsonObject(); + body.addProperty("model", settings.getLlmModel()); + body.addProperty("temperature", settings.getLlmTemperature()); + body.add("messages", messages); + if (responseJson) { + JsonObject responseFormat = new JsonObject(); + responseFormat.addProperty("type", "json_object"); + body.add("response_format", responseFormat); + } + + return executeHttp(buildChatUrl(), body.toString(), settings.getLlmMaxRetries()); + } + + /** + * Build the chat completions URL, respecting custom baseUrl. + */ + private String buildChatUrl() { + String baseUrl = settings.getOpenaiBaseUrl(); + if (baseUrl != null && !baseUrl.isEmpty()) { + return (baseUrl.endsWith("/") ? baseUrl : baseUrl + "/") + "chat/completions"; + } + return DEFAULT_CHAT_URL; + } + + /** + * Build the embeddings URL, respecting custom baseUrl. + */ + private String buildEmbedUrl() { + String baseUrl = settings.getOpenaiBaseUrl(); + if (baseUrl != null && !baseUrl.isEmpty()) { + return (baseUrl.endsWith("/") ? baseUrl : baseUrl + "/") + "embeddings"; + } + return DEFAULT_EMBED_URL; + } + + /** + * Execute an HTTP POST with manual retry and exponential backoff. + * 4xx client errors are NOT retried; 5xx server errors and network failures are. + */ + private String executeHttp(String url, String bodyJson, int maxRetries) { + int attempt = 0; + while (true) { + try { + String apiKey = settings.getOpenaiApiKey(); + if (apiKey == null || apiKey.isEmpty()) { + throw new IllegalStateException("OpenAI API key is required"); + } + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/json") + .header("Authorization", "Bearer " + apiKey) + .timeout(Duration.ofSeconds(120)) + .POST(HttpRequest.BodyPublishers.ofString(bodyJson)) + .build(); + + HttpResponse response = httpClient.send(request, + HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + return response.body(); + } + + if (response.statusCode() >= 400 && response.statusCode() < 500) { + // Client error — not retryable + throw new RuntimeException("OpenAI API client error: " + response.statusCode() + + " " + response.body()); + } + + // Server error — retry + attempt++; + if (attempt >= maxRetries) { + throw new RuntimeException("OpenAI API error after " + attempt + " retries: " + + response.statusCode() + " " + response.body()); + } + + long delay = Math.min(2000L * (long) Math.pow(1.5, attempt - 1), 10000); + log.warn("OpenAI API retry {}/{} after {}ms: status={}", attempt, maxRetries, delay, response.statusCode()); + Thread.sleep(delay); + + } catch (RuntimeException e) { + throw e; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("OpenAI API call interrupted", e); + } catch (Exception e) { + attempt++; + if (attempt >= maxRetries) { + throw new RuntimeException("OpenAI API call failed after " + attempt + " retries", e); + } + long delay = Math.min(2000L * (long) Math.pow(1.5, attempt - 1), 10000); + log.warn("OpenAI API retry {}/{} after {}ms: {}", attempt, maxRetries, delay, e.getMessage()); + try { Thread.sleep(delay); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException(ie); } + } + } + } + + /** + * Parse a single embedding from the API response by index. + */ + private List parseEmbeddingResponse(String response, int index) { + JsonObject jsonResponse = gson.fromJson(response, JsonObject.class); + JsonArray data = jsonResponse.getAsJsonArray("data"); + JsonArray embedding = data.get(index).getAsJsonObject().getAsJsonArray("embedding"); + List result = new ArrayList<>(embedding.size()); + for (int i = 0; i < embedding.size(); i++) { + result.add(embedding.get(i).getAsFloat()); + } + return result; + } + + private JsonObject buildMessage(String role, String content) { + JsonObject msg = new JsonObject(); + msg.addProperty("role", role); + msg.addProperty("content", content); + return msg; + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/TripletExtractor.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/TripletExtractor.java new file mode 100644 index 0000000..f4d29f2 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/llm/TripletExtractor.java @@ -0,0 +1,107 @@ +package com.zjkl.vectorgraphrag.llm; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.model.Document; +import com.zjkl.vectorgraphrag.model.Triplet; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Extracts knowledge triplets (subject-predicate-object) from text using LLM. + */ +@Slf4j +public class TripletExtractor { + + private static final String SYSTEM_PROMPT = + "You are an expert knowledge graph builder. Your task is to extract knowledge triplets from the given text.\n" + + "\n" + + "A triplet consists of:\n" + + "- Subject: An entity (person, place, thing, concept, etc.)\n" + + "- Predicate: The relationship between subject and object\n" + + "- Object: Another entity\n" + + "\n" + + "Guidelines:\n" + + "1. Extract all meaningful relationships from the text\n" + + "2. Keep entities concise but complete\n" + + "3. Use clear, specific predicates\n" + + "4. Extract both explicit and implicit relationships\n" + + "5. Ensure triplets are factually accurate based on the text\n" + + "\n" + + "Return your response as a JSON object with a \"triplets\" array, where each triplet is an array of [subject, predicate, object]."; + + private static final String EXAMPLE_INPUT = + "Text: Albert Einstein was born in Ulm, Germany in 1879. He developed the theory of relativity, which revolutionized physics. Einstein worked at the Institute for Advanced Study in Princeton."; + + private static final String EXAMPLE_OUTPUT = + "{\"triplets\": [[\"Albert Einstein\", \"was born in\", \"Ulm, Germany\"], [\"Albert Einstein\", \"was born in\", \"1879\"], [\"Albert Einstein\", \"developed\", \"the theory of relativity\"], [\"the theory of relativity\", \"revolutionized\", \"physics\"], [\"Albert Einstein\", \"worked at\", \"the Institute for Advanced Study\"], [\"the Institute for Advanced Study\", \"is located in\", \"Princeton\"]]}"; + + private final OpenAiClient openAiClient; + private final Gson gson; + + public TripletExtractor(VectorGraphRagSettings settings, OpenAiClient openAiClient) { + this.openAiClient = openAiClient; + this.gson = new Gson(); + } + + public List extract(String text) { + if (text == null || text.trim().isEmpty()) return List.of(); + + try { + List> examples = List.of( + Map.of("user", EXAMPLE_INPUT, "assistant", EXAMPLE_OUTPUT) + ); + String response = openAiClient.chat(SYSTEM_PROMPT, examples, "Text: " + text); + return parseResponse(response); + } catch (Exception e) { + log.warn("Triplet extraction failed: {}", e.getMessage()); + return List.of(); + } + } + + public List extractFromDocuments(List documents, boolean showProgress) { + for (int i = 0; i < documents.size(); i++) { + Document doc = documents.get(i); + List triplets = extract(doc.getText()); + doc.setTriplets(triplets); + // Store as raw arrays in metadata for backward compat + List> rawTriplets = triplets.stream() + .map(t -> List.of(t.getSubject(), t.getPredicate(), t.getObject())) + .collect(Collectors.toList()); + doc.getMetadata().put("triplets", rawTriplets); + if (showProgress) { + log.info("Extracted triplets for doc {}/{}: {} triplets", i + 1, documents.size(), triplets.size()); + } + } + return documents; + } + + private List parseResponse(String response) { + try { + JsonObject json = gson.fromJson(response, JsonObject.class); + JsonArray tripletsArray = json.getAsJsonArray("triplets"); + if (tripletsArray == null) return List.of(); + + List results = new ArrayList<>(); + for (int i = 0; i < tripletsArray.size(); i++) { + JsonArray arr = tripletsArray.get(i).getAsJsonArray(); + if (arr.size() >= 3) { + String subject = arr.get(0).getAsString().trim(); + String predicate = arr.get(1).getAsString().trim(); + String object = arr.get(2).getAsString().trim(); + if (!subject.isEmpty() && !predicate.isEmpty() && !object.isEmpty()) { + results.add(new Triplet(subject, predicate, object)); + } + } + } + return results; + } catch (Exception e) { + log.warn("Failed to parse triplet response: {}", e.getMessage()); + return List.of(); + } + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Document.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Document.java new file mode 100644 index 0000000..16cc3a3 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Document.java @@ -0,0 +1,24 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Document { + private String id; + private String text; + @Builder.Default + private Map metadata = new HashMap<>(); + @Builder.Default + private List triplets = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Entity.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Entity.java new file mode 100644 index 0000000..245ab5c --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Entity.java @@ -0,0 +1,31 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Objects; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Entity { + private String id; + private String name; + private List embedding; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Entity entity)) return false; + return name.equalsIgnoreCase(entity.name); + } + + @Override + public int hashCode() { + return Objects.hash(name.toLowerCase()); + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/EvictionResult.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/EvictionResult.java new file mode 100644 index 0000000..69337e2 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/EvictionResult.java @@ -0,0 +1,19 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EvictionResult { + @Builder.Default + private boolean occurred = false; + @Builder.Default + private int beforeCount = 0; + @Builder.Default + private int afterCount = 0; +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/ExtractionResult.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/ExtractionResult.java new file mode 100644 index 0000000..ee53dc9 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/ExtractionResult.java @@ -0,0 +1,28 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ExtractionResult { + @Builder.Default + private List documents = new ArrayList<>(); + @Builder.Default + private List entities = new ArrayList<>(); + @Builder.Default + private List relations = new ArrayList<>(); + @Builder.Default + private Map> entityToRelationIds = new HashMap<>(); + @Builder.Default + private Map> relationToPassageIds = new HashMap<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Passage.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Passage.java new file mode 100644 index 0000000..f66d08c --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Passage.java @@ -0,0 +1,23 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Passage { + private String id; + private String text; + @Builder.Default + private List entityIds = new ArrayList<>(); + @Builder.Default + private List relationIds = new ArrayList<>(); + private List embedding; +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/QueryResult.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/QueryResult.java new file mode 100644 index 0000000..ab96290 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/QueryResult.java @@ -0,0 +1,34 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class QueryResult { + private String query; + private String answer; + @Builder.Default + private List queryEntities = new ArrayList<>(); + @Builder.Default + private List retrievedPassages = new ArrayList<>(); + @Builder.Default + private List retrievedRelations = new ArrayList<>(); + @Builder.Default + private List expandedRelations = new ArrayList<>(); + @Builder.Default + private List rerankedRelations = new ArrayList<>(); + private Object subgraph; + @Builder.Default + private List passages = new ArrayList<>(); + private RetrievalDetail retrievalDetail; + private RerankResult rerankResult; + private EvictionResult evictionResult; +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Relation.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Relation.java new file mode 100644 index 0000000..e01fcbc --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Relation.java @@ -0,0 +1,22 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Relation { + private String id; + private String text; + private Triplet triplet; + @Builder.Default + private List sourcePassageIds = new ArrayList<>(); + private List embedding; +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RerankResult.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RerankResult.java new file mode 100644 index 0000000..d896b0b --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RerankResult.java @@ -0,0 +1,20 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RerankResult { + @Builder.Default + private List selectedRelationIds = new ArrayList<>(); + @Builder.Default + private List selectedRelationTexts = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalDetail.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalDetail.java new file mode 100644 index 0000000..e523aa5 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalDetail.java @@ -0,0 +1,28 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetrievalDetail { + @Builder.Default + private List entityIds = new ArrayList<>(); + @Builder.Default + private List entityTexts = new ArrayList<>(); + @Builder.Default + private List entityScores = new ArrayList<>(); + @Builder.Default + private List relationIds = new ArrayList<>(); + @Builder.Default + private List relationTexts = new ArrayList<>(); + @Builder.Default + private List relationScores = new ArrayList<>(); +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalResult.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalResult.java new file mode 100644 index 0000000..6f143f7 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/RetrievalResult.java @@ -0,0 +1,43 @@ +package com.zjkl.vectorgraphrag.model; + +import com.zjkl.vectorgraphrag.graph.SubGraph; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RetrievalResult { + @Builder.Default + private List entityIds = new ArrayList<>(); + @Builder.Default + private List entityTexts = new ArrayList<>(); + @Builder.Default + private List entityScores = new ArrayList<>(); + @Builder.Default + private List relationIds = new ArrayList<>(); + @Builder.Default + private List relationTexts = new ArrayList<>(); + @Builder.Default + private List relationScores = new ArrayList<>(); + private SubGraph subgraph; + @Builder.Default + private List expandedRelationIds = new ArrayList<>(); + @Builder.Default + private List expandedRelationTexts = new ArrayList<>(); + private String query; + @Builder.Default + private List queryEntities = new ArrayList<>(); + @Builder.Default + private boolean evictionOccurred = false; + @Builder.Default + private int evictionBeforeCount = 0; + @Builder.Default + private int evictionAfterCount = 0; +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Triplet.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Triplet.java new file mode 100644 index 0000000..ff9cbfc --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/model/Triplet.java @@ -0,0 +1,40 @@ +package com.zjkl.vectorgraphrag.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Objects; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Triplet { + private String subject; + private String predicate; + private String object; + + public String toRelationText() { + return subject + " " + predicate + " " + object; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Triplet triplet)) return false; + return subject.equalsIgnoreCase(triplet.subject) + && predicate.equalsIgnoreCase(triplet.predicate) + && object.equalsIgnoreCase(triplet.object); + } + + @Override + public int hashCode() { + return Objects.hash( + subject.toLowerCase(), + predicate.toLowerCase(), + object.toLowerCase() + ); + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/EmbeddingClient.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/EmbeddingClient.java new file mode 100644 index 0000000..b933930 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/EmbeddingClient.java @@ -0,0 +1,92 @@ +package com.zjkl.vectorgraphrag.storage; + +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import com.zjkl.vectorgraphrag.llm.OpenAiClient; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unified embedding model wrapper. + * Supports OpenAI embedding models. + */ +@Slf4j +public class EmbeddingClient { + + private final VectorGraphRagSettings settings; + private final OpenAiClient openAiClient; + private Integer dimension; + + public EmbeddingClient(VectorGraphRagSettings settings, OpenAiClient openAiClient) { + this.settings = settings; + this.openAiClient = openAiClient; + } + + public int getDimension() { + if (dimension == null) { + List test = embed("test"); + dimension = test.size(); + } + return dimension; + } + + public List embed(String text) { + List raw = openAiClient.embed(text); + return l2Normalize(raw); + } + + public List> embedBatch(List texts) { + return embedBatch(texts, false); + } + + public List> embedBatch(List texts, boolean showProgress) { + List> results = new ArrayList<>(); + for (int i = 0; i < texts.size(); i += settings.getBatchSize()) { + int end = Math.min(i + settings.getBatchSize(), texts.size()); + List batch = texts.subList(i, end); + try { + // Use batch API: all texts in one HTTP call + List> batchResults = openAiClient.embedBatch(batch); + for (List vec : batchResults) { + results.add(vec != null ? l2Normalize(vec) : fallbackVector()); + } + } catch (Exception e) { + log.warn("Batch embedding failed, falling back to single: {}", e.getMessage()); + for (String text : batch) { + try { + results.add(embed(text)); + } catch (Exception e2) { + log.warn("Embedding failed for text, using zero vector: {}", e2.getMessage()); + results.add(fallbackVector()); + } + } + } + if (showProgress) { + log.info("Embedded {}/{} texts", end, texts.size()); + } + } + return results; + } + + private List fallbackVector() { + List zero = new ArrayList<>(); + for (int j = 0; j < getDimension(); j++) zero.add(0.0f); + return zero; + } + + private List l2Normalize(List vector) { + double sum = 0.0; + for (float v : vector) { + sum += v * v; + } + double norm = Math.sqrt(sum); + if (norm == 0) return vector; + + List normalized = new ArrayList<>(vector.size()); + for (float v : vector) { + normalized.add((float) (v / norm)); + } + return normalized; + } +} diff --git a/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/MilvusStore.java b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/MilvusStore.java new file mode 100644 index 0000000..e3a0399 --- /dev/null +++ b/VectorGraphRag/src/main/java/com/zjkl/vectorgraphrag/storage/MilvusStore.java @@ -0,0 +1,621 @@ +package com.zjkl.vectorgraphrag.storage; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.zjkl.vectorgraphrag.config.VectorGraphRagSettings; +import io.milvus.v2.client.MilvusClientV2; +import io.milvus.v2.client.ConnectConfig; +import io.milvus.v2.common.ConsistencyLevel; +import io.milvus.v2.common.DataType; +import io.milvus.v2.common.IndexParam; +import io.milvus.v2.service.vector.request.data.BaseVector; +import io.milvus.v2.service.vector.request.data.FloatVec; +import io.milvus.v2.service.collection.request.CreateCollectionReq; +import io.milvus.v2.service.collection.request.DropCollectionReq; +import io.milvus.v2.service.collection.request.HasCollectionReq; +import io.milvus.v2.service.index.request.CreateIndexReq; +import io.milvus.v2.service.vector.request.InsertReq; +import io.milvus.v2.service.vector.request.QueryReq; +import io.milvus.v2.service.vector.request.SearchReq; +import io.milvus.v2.service.vector.request.UpsertReq; +import io.milvus.v2.service.vector.response.InsertResp; +import io.milvus.v2.service.vector.response.QueryResp; +import io.milvus.v2.service.vector.response.SearchResp; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Milvus vector store for entities, relations, and passages. + * + * Manages three collections: + * - Entity collection: entities with embeddings and adjacency metadata + * - Relation collection: relations with embeddings and triplet fields + * - Passage collection: passages with embeddings + */ +@Slf4j +public class MilvusStore { + + private final VectorGraphRagSettings settings; + private final EmbeddingClient embeddingClient; + private final MilvusClientV2 client; + private final Gson gson; + + private final String entityCollection; + private final String relationCollection; + private final String passageCollection; + + public MilvusStore(VectorGraphRagSettings settings, EmbeddingClient embeddingClient) { + this.settings = settings; + this.embeddingClient = embeddingClient; + this.gson = new Gson(); + + ConnectConfig.ConnectConfigBuilder builder = ConnectConfig.builder() + .uri(settings.getMilvusUri()); + if (settings.getMilvusToken() != null && !settings.getMilvusToken().isEmpty()) { + builder.token(settings.getMilvusToken()); + } + if (settings.getMilvusDb() != null && !settings.getMilvusDb().isEmpty()) { + builder.dbName(settings.getMilvusDb()); + } + this.client = new MilvusClientV2(builder.build()); + + String prefix = settings.hasCollectionPrefix() ? settings.getCollectionPrefix() + "_" : ""; + this.entityCollection = prefix + settings.getEntityCollection(); + this.relationCollection = prefix + settings.getRelationCollection(); + this.passageCollection = prefix + settings.getPassageCollection(); + } + + // ==================== Collection Management ==================== + + public void createCollections(boolean dropExisting) { + for (String name : List.of(entityCollection, relationCollection, passageCollection)) { + createCollection(name, dropExisting); + } + } + + public void dropCollections() { + for (String name : List.of(entityCollection, relationCollection, passageCollection)) { + try { + if (client.hasCollection(HasCollectionReq.builder().collectionName(name).build())) { + client.dropCollection(DropCollectionReq.builder().collectionName(name).build()); + log.info("Dropped collection: {}", name); + } + } catch (Exception e) { + log.warn("Error dropping collection {}: {}", name, e.getMessage()); + } + } + } + + private void createCollection(String collectionName, boolean dropExisting) { + try { + if (client.hasCollection(HasCollectionReq.builder().collectionName(collectionName).build())) { + if (dropExisting) { + client.dropCollection(DropCollectionReq.builder().collectionName(collectionName).build()); + } else { + return; + } + } + } catch (Exception e) { + log.warn("Error checking collection {}: {}", collectionName, e.getMessage()); + } + + int dim = settings.getEmbeddingDimension() > 0 + ? settings.getEmbeddingDimension() + : embeddingClient.getDimension(); + + CreateCollectionReq.CollectionSchema schema = CreateCollectionReq.CollectionSchema.builder().build(); + schema.addField(io.milvus.v2.service.collection.request.AddFieldReq.builder() + .fieldName("id") + .dataType(DataType.VarChar) + .maxLength(64) + .isPrimaryKey(true) + .autoID(false) + .build()); + schema.addField(io.milvus.v2.service.collection.request.AddFieldReq.builder() + .fieldName("vector") + .dataType(DataType.FloatVector) + .dimension(dim) + .build()); + schema.addField(io.milvus.v2.service.collection.request.AddFieldReq.builder() + .fieldName("text") + .dataType(DataType.VarChar) + .maxLength(65535) + .build()); + // enableDynamicField is true by default + + client.createCollection(CreateCollectionReq.builder() + .collectionName(collectionName) + .collectionSchema(schema) + .consistencyLevel(ConsistencyLevel.fromName(settings.getMilvusConsistencyLevel())) + .build()); + + // Create index + IndexParam.IndexParamBuilder paramBuilder = IndexParam.builder() + .fieldName("vector") + .indexType(IndexParam.IndexType.valueOf(settings.getMilvusIndexType())) + .metricType(IndexParam.MetricType.valueOf(settings.getMilvusMetricType())); + if (settings.getMilvusIndexParams() != null && !settings.getMilvusIndexParams().isEmpty()) { + paramBuilder.indexName("vector_index"); + paramBuilder.extraParams(settings.getMilvusIndexParams()); + } + client.createIndex(CreateIndexReq.builder() + .collectionName(collectionName) + .indexParams(List.of(paramBuilder.build())) + .build()); + + log.info("Created collection: {} (dim={})", collectionName, dim); + } + + // ==================== Generic Insert ==================== + + private List insertData(String collectionName, List ids, List texts, + List> embeddings, List> metadatas, + boolean showProgress) { + if (ids == null || ids.isEmpty()) return List.of(); + + int batchSize = settings.getBatchSize(); + List resultIds = new ArrayList<>(); + + for (int i = 0; i < ids.size(); i += batchSize) { + int end = Math.min(i + batchSize, ids.size()); + List batch = new ArrayList<>(); + + for (int j = i; j < end; j++) { + JsonObject row = new JsonObject(); + row.addProperty("id", ids.get(j)); + row.addProperty("text", texts.get(j)); + + JsonArray vectorArr = new JsonArray(); + List vec = embeddings.get(j); + for (float v : vec) vectorArr.add(v); + row.add("vector", vectorArr); + + if (metadatas != null && j < metadatas.size() && metadatas.get(j) != null) { + Map meta = metadatas.get(j); + for (Map.Entry entry : meta.entrySet()) { + if (entry.getValue() instanceof List) { + JsonArray arr = new JsonArray(); + for (Object item : (List) entry.getValue()) { + arr.add(item.toString()); + } + row.add(entry.getKey(), arr); + } else if (entry.getValue() instanceof String) { + row.addProperty(entry.getKey(), (String) entry.getValue()); + } else if (entry.getValue() instanceof Number) { + row.addProperty(entry.getKey(), (Number) entry.getValue()); + } else if (entry.getValue() instanceof Boolean) { + row.addProperty(entry.getKey(), (Boolean) entry.getValue()); + } + } + } + + batch.add(row); + resultIds.add(ids.get(j)); + } + + InsertReq insertReq = InsertReq.builder() + .collectionName(collectionName) + .data(batch) + .build(); + client.insert(insertReq); + + if (showProgress) { + log.info("Inserted {}/{} into {}", end, ids.size(), collectionName); + } + } + + return resultIds; + } + + // ==================== Entity Operations ==================== + + public List insertEntities(List entityTexts, List ids, + List> embeddings, List> metadatas, + boolean showProgress) { + if (entityTexts == null || entityTexts.isEmpty()) return List.of(); + + List> embeds = embeddings != null ? embeddings + : embeddingClient.embedBatch(entityTexts, showProgress); + List finalIds = ids != null ? ids : entityTexts.stream() + .map(t -> UUID.randomUUID().toString()).collect(Collectors.toList()); + + return insertData(entityCollection, finalIds, entityTexts, embeds, metadatas, showProgress); + } + + public List> searchEntities(List> queryEmbeddings, int topK) { + List floatVecs = queryEmbeddings.stream() + .map(FloatVec::new) + .collect(Collectors.toList()); + SearchReq searchReq = SearchReq.builder() + .collectionName(entityCollection) + .data(floatVecs) + .topK(topK) + .outputFields(List.of("id", "text", "relation_ids", "passage_ids")) + .build(); + + SearchResp resp = client.search(searchReq); + return convertSearchResults(resp); + } + + public List> searchRelations(List queryEmbedding, int topK) { + SearchReq searchReq = SearchReq.builder() + .collectionName(relationCollection) + .data(Collections.singletonList(new FloatVec(queryEmbedding))) + .topK(topK) + .outputFields(List.of("id", "text", "entity_ids", "passage_ids", "subject", "predicate", "object")) + .build(); + + SearchResp resp = client.search(searchReq); + return convertSearchResults(resp); + } + + public List> searchPassages(List queryEmbedding, int topK, String filter) { + SearchReq.SearchReqBuilder builder = SearchReq.builder() + .collectionName(passageCollection) + .data(Collections.singletonList(new FloatVec(queryEmbedding))) + .topK(topK) + .outputFields(List.of("id", "text", "entity_ids", "relation_ids")); + if (filter != null && !filter.isEmpty()) { + builder.filter(filter); + } + + SearchResp resp = client.search(builder.build()); + return convertSearchResults(resp); + } + + // ==================== Relation Operations ==================== + + public List insertRelations(List relationTexts, List ids, + List> embeddings, List> metadatas, + boolean showProgress) { + if (relationTexts == null || relationTexts.isEmpty()) return List.of(); + + List> embeds = embeddings != null ? embeddings + : embeddingClient.embedBatch(relationTexts, showProgress); + List finalIds = ids != null ? ids : relationTexts.stream() + .map(t -> UUID.randomUUID().toString()).collect(Collectors.toList()); + + return insertData(relationCollection, finalIds, relationTexts, embeds, metadatas, showProgress); + } + + // ==================== Passage Operations ==================== + + public List insertPassages(List passageTexts, List ids, + List> embeddings, List> metadatas, + boolean showProgress) { + if (passageTexts == null || passageTexts.isEmpty()) return List.of(); + + List> embeds = embeddings != null ? embeddings + : embeddingClient.embedBatch(passageTexts, showProgress); + List finalIds = ids != null ? ids : passageTexts.stream() + .map(t -> UUID.randomUUID().toString()).collect(Collectors.toList()); + + return insertData(passageCollection, finalIds, passageTexts, embeds, metadatas, showProgress); + } + + // ==================== Query by ID ==================== + + public List> getEntitiesByIds(List entityIds) { + if (entityIds == null || entityIds.isEmpty()) return List.of(); + + String idsStr = entityIds.stream() + .map(id -> "\"" + id + "\"") + .collect(Collectors.joining(", ")); + QueryResp resp = client.query(QueryReq.builder() + .collectionName(entityCollection) + .filter("id in [" + idsStr + "]") + .outputFields(List.of("id", "text", "relation_ids", "passage_ids")) + .build()); + return convertQueryResults(resp); + } + + public List> getRelationsByIds(List relationIds) { + if (relationIds == null || relationIds.isEmpty()) return List.of(); + + String idsStr = relationIds.stream() + .map(id -> "\"" + id + "\"") + .collect(Collectors.joining(", ")); + QueryResp resp = client.query(QueryReq.builder() + .collectionName(relationCollection) + .filter("id in [" + idsStr + "]") + .outputFields(List.of("id", "text", "entity_ids", "passage_ids", "subject", "predicate", "object")) + .build()); + return convertQueryResults(resp); + } + + public List> getPassagesByIds(List passageIds) { + return getPassagesByIds(passageIds, null); + } + + public List> getPassagesByIds(List passageIds, String filter) { + if (passageIds == null || passageIds.isEmpty()) return List.of(); + + String idsStr = passageIds.stream() + .map(id -> "\"" + id + "\"") + .collect(Collectors.joining(", ")); + String filterExpr = "id in [" + idsStr + "]"; + if (filter != null && !filter.isEmpty()) { + filterExpr = "(" + filterExpr + ") and (" + filter + ")"; + } + + QueryResp resp = client.query(QueryReq.builder() + .collectionName(passageCollection) + .filter(filterExpr) + .outputFields(List.of("id", "text", "entity_ids", "relation_ids")) + .build()); + return convertQueryResults(resp); + } + + public List queryPassageIds(String filter) { + if (filter == null || filter.trim().isEmpty()) return List.of(); + + QueryResp resp = client.query(QueryReq.builder() + .collectionName(passageCollection) + .filter(filter) + .outputFields(List.of("id")) + .build()); + return resp.getQueryResults().stream() + .map(r -> r.getEntity().get("id").toString()) + .collect(Collectors.toList()); + } + + // ==================== Update / Upsert ==================== + + public boolean upsertEntity(String entityId, String text, List embedding, + List relationIds, List passageIds) { + List> existing = getEntitiesByIds(List.of(entityId)); + if (existing.isEmpty()) return false; + + Map data = existing.get(0); + JsonObject update = new JsonObject(); + update.addProperty("id", entityId); + update.addProperty("text", text != null ? text : (String) data.get("text")); + + if (embedding != null) { + JsonArray arr = new JsonArray(); + for (float v : embedding) arr.add(v); + update.add("vector", arr); + } else { + List newEmbed = embeddingClient.embed(update.get("text").getAsString()); + JsonArray arr = new JsonArray(); + for (float v : newEmbed) arr.add(v); + update.add("vector", arr); + } + + if (relationIds != null) { + JsonArray arr = new JsonArray(); + for (String id : relationIds) arr.add(id); + update.add("relation_ids", arr); + } + if (passageIds != null) { + JsonArray arr = new JsonArray(); + for (String id : passageIds) arr.add(id); + update.add("passage_ids", arr); + } + + client.upsert(UpsertReq.builder().collectionName(entityCollection).data(List.of(update)).build()); + return true; + } + + public boolean upsertRelation(String relationId, String text, List embedding, + List entityIds, List passageIds, + String subject, String predicate, String object) { + List> existing = getRelationsByIds(List.of(relationId)); + if (existing.isEmpty()) return false; + + Map data = existing.get(0); + JsonObject update = new JsonObject(); + update.addProperty("id", relationId); + update.addProperty("text", text != null ? text : (String) data.get("text")); + + String finalText = update.get("text").getAsString(); + if (embedding != null) { + JsonArray arr = new JsonArray(); + for (float v : embedding) arr.add(v); + update.add("vector", arr); + } else { + List newEmbed = embeddingClient.embed(finalText); + JsonArray arr = new JsonArray(); + for (float v : newEmbed) arr.add(v); + update.add("vector", arr); + } + + if (entityIds != null) { + JsonArray arr = new JsonArray(); + for (String id : entityIds) arr.add(id); + update.add("entity_ids", arr); + } + if (passageIds != null) { + JsonArray arr = new JsonArray(); + for (String id : passageIds) arr.add(id); + update.add("passage_ids", arr); + } + if (subject != null) update.addProperty("subject", subject); + if (predicate != null) update.addProperty("predicate", predicate); + if (object != null) update.addProperty("object", object); + + client.upsert(UpsertReq.builder().collectionName(relationCollection).data(List.of(update)).build()); + return true; + } + + public boolean upsertPassage(String passageId, String text, List embedding, + List entityIds, List relationIds) { + List> existing = getPassagesByIds(List.of(passageId)); + if (existing.isEmpty()) return false; + + Map data = existing.get(0); + JsonObject update = new JsonObject(); + update.addProperty("id", passageId); + update.addProperty("text", text != null ? text : (String) data.get("text")); + + String finalText = update.get("text").getAsString(); + if (embedding != null) { + JsonArray arr = new JsonArray(); + for (float v : embedding) arr.add(v); + update.add("vector", arr); + } else { + List newEmbed = embeddingClient.embed(finalText); + JsonArray arr = new JsonArray(); + for (float v : newEmbed) arr.add(v); + update.add("vector", arr); + } + + if (entityIds != null) { + JsonArray arr = new JsonArray(); + for (String id : entityIds) arr.add(id); + update.add("entity_ids", arr); + } + if (relationIds != null) { + JsonArray arr = new JsonArray(); + for (String id : relationIds) arr.add(id); + update.add("relation_ids", arr); + } + + client.upsert(UpsertReq.builder().collectionName(passageCollection).data(List.of(update)).build()); + return true; + } + + // ==================== Delete Operations ==================== + + public boolean deleteEntity(String entityId) { + return deleteById(entityCollection, entityId); + } + + public boolean deleteRelation(String relationId) { + return deleteById(relationCollection, relationId); + } + + public boolean deletePassage(String passageId) { + return deleteById(passageCollection, passageId); + } + + public int deleteEntities(List entityIds) { + return deleteByIds(entityCollection, entityIds); + } + + public int deleteRelations(List relationIds) { + return deleteByIds(relationCollection, relationIds); + } + + public int deletePassages(List passageIds) { + return deleteByIds(passageCollection, passageIds); + } + + private boolean deleteById(String collection, String id) { + try { + client.delete(io.milvus.v2.service.vector.request.DeleteReq.builder() + .collectionName(collection) + .filter("id == \"" + id + "\"") + .build()); + return true; + } catch (Exception e) { + log.warn("Delete failed for {} in {}: {}", id, collection, e.getMessage()); + return false; + } + } + + private int deleteByIds(String collection, List ids) { + if (ids == null || ids.isEmpty()) return 0; + String idsStr = ids.stream().map(id -> "\"" + id + "\"").collect(Collectors.joining(", ")); + client.delete(io.milvus.v2.service.vector.request.DeleteReq.builder() + .collectionName(collection) + .filter("id in [" + idsStr + "]") + .build()); + return ids.size(); + } + + // ==================== Utility ==================== + + public Map getCollectionStats() { + Map stats = new HashMap<>(); + stats.put("entityCount", 0); + stats.put("relationCount", 0); + stats.put("passageCount", 0); + + try { + // MilvusClientV2 doesn't have getCollectionStats directly; + // We'll do a rough count by querying all IDs + } catch (Exception e) { + log.warn("Error getting collection stats: {}", e.getMessage()); + } + return stats; + } + + /** + * Search relations with a custom filter expression (for eviction strategy). + */ + public List> searchRelationsWithFilter(List queryEmbedding, + int topK, String filter) { + SearchReq.SearchReqBuilder builder = SearchReq.builder() + .collectionName(relationCollection) + .data(Collections.singletonList(new FloatVec(queryEmbedding))) + .topK(topK) + .outputFields(List.of("id", "text")); + if (filter != null && !filter.isEmpty()) { + builder.filter(filter); + } + + SearchResp resp = client.search(builder.build()); + return convertSearchResults(resp); + } + + public MilvusClientV2 getClient() { + return client; + } + + public String getRelationCollection() { + return relationCollection; + } + + // ==================== Result Conversion ==================== + + private List> convertSearchResults(SearchResp resp) { + List> results = new ArrayList<>(); + if (resp.getSearchResults() == null) return results; + + for (List resultList : resp.getSearchResults()) { + for (SearchResp.SearchResult r : resultList) { + Map map = new HashMap<>(); + map.put("id", r.getId()); + map.put("distance", r.getScore()); + + Map entity = r.getEntity(); + Map flat = new HashMap<>(); + if (entity != null) { + for (Map.Entry e : entity.entrySet()) { + flat.put(e.getKey(), e.getValue()); + } + } + map.put("entity", flat); + results.add(map); + } + } + return results; + } + + private List> convertQueryResults(QueryResp resp) { + List> results = new ArrayList<>(); + if (resp.getQueryResults() == null) return results; + + for (QueryResp.QueryResult r : resp.getQueryResults()) { + Map map = new HashMap<>(); + Map entity = r.getEntity(); + if (entity != null) { + map.putAll(entity); + } + results.add(map); + } + return results; + } + + public static String combineFilters(String... filters) { + return Arrays.stream(filters) + .filter(f -> f != null && !f.trim().isEmpty()) + .map(String::trim) + .map(f -> "(" + f + ")") + .collect(Collectors.joining(" and ")); + } +} diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/VectorGraphRAG.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/VectorGraphRAG.class new file mode 100644 index 0000000000000000000000000000000000000000..8b3f7d350f0deb04c23be91114a79e188154aee4 GIT binary patch literal 21555 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 OfavJ^{2>2`jQ<77cRlm~ literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/Graph.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/Graph.class new file mode 100644 index 0000000000000000000000000000000000000000..887b8361387909583fe49c19d06d77a0ba241566 GIT binary patch literal 12731 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 literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraph.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraph.class new file mode 100644 index 0000000000000000000000000000000000000000..8b7f5763b5bd339f2e0be7d30d67e64944887ed7 GIT binary patch literal 14527 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 literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage$SubGraphPassageBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage$SubGraphPassageBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..fc4e81495b629460a54ac4ef22c42b4f76b2dd25 GIT binary patch literal 2933 zcmb_e>r&fB6#mv21dhOj5JCzKq;*ovC2rCSZB1x^giC86#grr@{js(;Mp#IUv}Q`5 zq|;x0gm$KxWRjUaK%Xho$yrGlA&E?w;fMBe_MG#b+n&{b|G)khz#M+bAcZy!X&vq8 zVCdcD2fSc%t6o^I?24*n=$J7qL(Vd^jpetx(1|V$866j(Gu*G*dxhV28)o5vcx|Wd z@ckW!*9+dFP;OS16y+gzU0xTt$bPLIvU+EaTEFHtD7ZqBMj;w-8OYy5z zgo`@*aET!+ENRHYm71G7;AT^h@xF$pG|WQDaHS`IS;qjbFmxZYyMo+e+e+D09Um!W z7ad`8Y1mdvojM)X@v)N4hEGX4gAt5sxUS<9e9AC&rYMl7xte&+o2JaQY$D=VK5D*# zxuN5x!su_wgltg^V=8lbhNZE1{7$1BM<@!J-^ySDlNzRU+(O|*LHJ2w(7bT3KWDfZ z#`No@7{wxDz)1>?%)fCD|@^l7Hq4^yu%qV7J3eL@r3!!_)&|Xo!is3fh(laHCveI3ayxLgh z`(D;HEHU(Wt*#Y4hE8c8U9bM5Mi4G?hD_ORI#sb~sA}qubkbW&A8A<=u3WZVYHz*s zwk=&r-FH>U9lPdsVx8_-R4%d)I`WuNyUQj=RmW9xEAf7#RisdGj)?he2Y$+617!`H z>bCz(x8}H|8`go{5Cz{$zX2?A^=2G0{2s2`fYCR5nOikexVe&TH=6s!_@xU`P6%#N z;Uus>4e=*5tU$#AH_fsk1tm{kv8W*|nDl}Px~c=o0n_k=;YQ5aBp)<9Ww`c!R(f=O zhjE==p%k^x4jSpj1;dx#j^QhsQ|f7q(dfC0(dfk_?yo(W>4*+`;$r;tD4xQvkq-J* zpwn+?RUk>GDB~}|{`S;=OJj#e)bSmym4Qm6h#8v0<}-5XZlI`0vvO1$pLjvTU$jgi zs%pSz2~-htLQJUnCM)g!V5RY(GR)$8w0SOX1eWT`(%$j(3-o)M+fFf8Z<(u;mP-_k zd*qxS6-AjQil3OdNOb0tF$Wdq&&!&m?fX;f5dW&8Si*J#oF%qq1tOS-X61u9n;UlYP?tO)Eng(fljn9GP0`s#n uoKUOn_<=O0@Z$;8l1CfCD$SjQ`H;RfY|*ZdcsuF$>=C-~7~6P;tM35$_PP-O literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphPassage.class new file mode 100644 index 0000000000000000000000000000000000000000..86533f6156d488229ca1e6a01294bb90f4b44743 GIT binary patch literal 4496 zcmbtY-*X$)75=WgtCi%9Ez7Zk5*I=v5?lVEmeL={NlIc8$E}^DaT*$+Eo*CIZ!GT` zY2{){OIv0bo|xf@PG@)}Go3sD(}WJ4>A(w}>EBdJzq7lNR%;m&>an$F&;9Oq&#!y# zmH++UPyPwu9NsXHQW(8$?OK(V@6;>j8Vzf2*=hPYC}<{hq!rSq9oO;CDhy0c-7t_* zcy`^}uDp7Ct6tf)*L|&$pa<&2HpiK+9qf zrh!8yhA^x!`%uIRDW|4TSPmShTkb|>)o(cN#=Ovum?#LR=G(9MqBv|~4C4w}+w~oP zZ>iQ)$cJ+S=f&?}<|8JG0vv4Eb<1}=m(Uyuj+vOiw-hq#mV4plmQ`06n~W`fW$iY@ zF+cUZfFCn)9FHsL8@9hhD-Taj#h{U$Ih;Vrz!N4;3UR*cNXW(D+pVL03$CN6Lpx|eeJ z0e)!UM<$*|wa38F16s3d)m!$JTM8%p#bUqD1(x1v6KBARI@tOPwvau0Sw2kwV3B^d&%8( znhxilb6w95%9LR%EZ4p5HE*l3XuEd9^6eTIHP*r%r*Mg@Jk%CDVDFN&uZVJQU zXiSq2AU!2F5`ubkhgN-SeQU+qiISjSy|%P+fd((JeKhPQ%bJ@xutqOMmUQc!5iRx5 zWqhx_w-+B`6Lu4j*a<;Gyl=wPH#Z6Pz8J}0Zq;iw*6oXq?5@L!BWO+)EizU zx061EN0NkN4@`IstC6c!J|*Yr^7K9AK1>8{Fkl=H5mC^j7No{hB7E2TbLJnEQ|dLz z`E%Te9AA#xIVzk3vE&|PXIT5s5gjHz&8zMrR|&)Xi-ZR^`>%H7L01cRR(!SMSFFaX zEq!9etJnA(q>Udr_DMvhbBOf+0|G|)f!7ngw-~@j& z>I*y)irE9io*K~Pn@pG$-t75BioCj{LmZ8FlX$`D9Y=M#Cyw^^6@GyTDb<^N8f4nZ z&!5)L1nHc}&u=oBnf&w}7_;~B-Iqjvs;bFAQHw@0lHzcvT-AdiW;d9WDeCQ^xoSEX zN_U2sbIzLRpQcNpEs^yD*v2hv(0ZMT*rb$VU~j>pM*}=uR&bk=hO>B*pN}~{KEXVYY`S43gzaS_ie+#9`QL&t|Gey^0{+qR$M`Xc zpSg!oJ{ImF=rQpEI~42XqX*EsjIW%SZ;@8#^JqXTeY`w#5Bc(}&=<9cJ>D;e0`{lE zS)KAd8ufKD1-A#O{-g5G0j?vG^fwLC-@+3?#uhtciyRC4s@D@>4Lh8X!pq#lazo)a e0yHUQDDCpk$7_5m5Wy_scih*%#~<(~6#obNHHhf| literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation$SubGraphRelationBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation$SubGraphRelationBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..f1517c9d6d2c861b71aad2647758c01d9f2eef55 GIT binary patch literal 3486 zcmb_e>rxz55dO|`8CZva5J1eupqsc0$ZEXHMG};NEQzv642hT7-2+S*W~iOBlvri? z4*s%y27kmVQ%S`tAHZiyS$=0`*j;vp6jbqJ&ZSSE?mpdLchA57J^Kg14Q!^7LYskh z6CLOj=zD1GTY1NFxAJ#N4`o>ibWYo@t!4$adAdG_}*KGrnr#0xk;lN>|zH zV5#C~_ARF-`SwtKP1#PqVEZaie%ZupxFXQgVD}}xA~v-A*G;^kh4t-OzHe>Gx-@-w z)xjFP#^z;C= z5pMd4?oUiiVOn5#*V>Wuo=Z^NwbeFPzOr293;fzFEV_BN&u+FUE;+$)feWiOB6C+R zx%;+nmmGP+bv+g24^8ebINol_+sWUOuB;N~l_`S0Xm7ces#S^NOpAY~<7#JlrG4J3 zkh`~FyYhBzweiyzG_$79+l@RritX-KA6IXPP&~wxp^s?R&^d@WsdR0eASpNggmMT6Ya=o3{ zNaH>p82DD#lkb>ejV@)o``(Vshn@&a%z~vG;eo(!%?OVe!!ywY{l$ zf;Lf(TwEi(64>uI@h6nTNW{G5I7M4Y2H0G3Sv=+)K36iWhmUcofs(-0*lUv>VSr$} z{9;zN;qb*6Wp_-mLU(iIe*^?(xa;IR%Q>aneT>GAAEUA3$7t;LF&aB~jK-e;YWg(L zH`k({Z9B%#K7R~ma~H59T$qR5=!PgeP4p*<%S8V?8?MY7Po6AO(;lyxFm=)j4E z#vvj23z+EBp%V*@V@lu_7SR?&d^HM`sRK1K*8Uim0?BR1M9Zv4%cPWx1jbSw6q+(e zN{GuZTEMZKtaDWB%$!)~a!lv)3v?E+!uM%p|G|81<2*a|7e)#kF8vPUDc;n}(G?Dv zVE@+2-^kwM*5KE}uaDmVzoGGoCwN=qxIN~XE1~4bGadL?|D@9ogUIPWY+9gwq|qLp zX&;4WbEMto**T=1qtC#d=ji3w;<>M&qoiN4${f+@m!(B93rQP!ig!7Ua(YHHkeqkA t#!yB=3U{E$lN8pDSnzc~%VM2#7w_KVcNgDt*H7LqO8SA`wNQq{$p0tZ8G`@- literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/graph/SubGraphRelation.class new file mode 100644 index 0000000000000000000000000000000000000000..0961b5dc0fbe919a52db44683f8f78ffb0869864 GIT binary patch literal 6052 zcmcgw>vJ1d75}Zh((19c6+3aVG?b)OQ(IQzKp+s=2}w*IE_M>^kdT%~*Ve|~Sk^ky z$~1-2LU}(+d9;-G2gnSQ86Ja^Okq0oOPS#_pWqXJ1z!l|cXn6OYQ0Vzn39RSXV3ZF z-@W(TbIv`|U;h2-YXFYn=Nh^c3|ui+&C!NyS4NN3YUZ^myY6P7K-G~zQbBUuuG;Pq z1>Hl#7c`_4oSb)-N1wj3R2f~h=3S?@P%~E+Yv#hJCydTE=1z%b#;TaE?Nswo#qow+ zDOT(ThF>`|gigL6==t&_Ctvp<-4SMrYlcU0oOx-Yq)%g;aH|r(98N z)v-+!TD>uMg-aLRb{#uJmtLt^WqaOqEz!PB#{;5GIxXPabv%f75NK6h+r2hft}Dp- z6MN1Rzj@Q{*71-4Gb?7jZZ23vW=NUW@d)-PNX?to6IUB%MZvbA(8AApGmQ;DF5n>@ z!zd_7ELiR&cer(EI0Oy$m_ZSHHSE(dD#W?A6MQZ%-;#;E>EEg2UBal5@jU$@v%Fi! zdqkI^j)x>J5%qg@yie3R)#sXC5kpDGm>AMD_*01Xu#O{mzYjmr_Dz3t$!+fl`k0R6 zg6{QDF-#V?d_C7&r`h1dRq^7ij`QNh z{(RZGY&I%xz7>^XzM$ixmx{kD$wd%NDfuOJZrz+0!oU=4~%Bos5 zCSjSAYIA;}Q1BRMxxdP=QPCl7|CBRtRxX$|TecAFLv(LF;@YB`&4YrXe+=2q2J z(B}g}nyd$Lyuw6}`S#|kKfV?At?^-vKSgMZxnPcvs%O?U=a;6b()3inYX;cv|}cc=Uxo` z;{P{)Y!F7)6pN8S&CEKD+PrnrmWs2DDb&$l?2~(sUOr>h-Dyi|libY59mlP^>_et4 zchM==Q}~X8C!%AA?DAoyxJ!;zp24w-*g95u@sCxcR&;roRu~;thWnEEUIyRCOB!C5 zyX6NguI(GyuC6*uR?waJ*Ud>&nx|_DUJf5a0Q6UV+N_o^c~7=--jnT{_hiH7J=vwPef@|hUm~8(Sm=E_ zGIDjI8;=vQi+1^!`U8|px6u6?$_x|!P4Wro0nbPAu|W56J~MK={!a{Pd;(8$?#LQ6 zt|7gC4dJ;JX$*srqgeY$9Wb z2BJj$_atK58ACJ}B^tOV5!=)lA|pz)^`1oRY=eUiJ9}r8XfTGzkHF5zQKb2eA>0)u z+_7oGGOS>$B|asblZBBrWPTfohpfjq=p%x7kT93DQX-LYIi54OSx!mODCa^v=fGw; zCEcT(i}9R;o8^?!5#_YwIgQP7N*RiBUcpju=u_b{+9{mfp`6|5jQo;TA==O9B)^JY z;w*lMEk{nT8b8~v&Ccc*%<0Y0v#>&5p=YaGx`LS3qXBFt_f0a#2)(%-+9f{RCdF`3J-ak zqT?#dcNg-wgBo?+tZx5Aosx=E_#0eG2~6X!Xi!R`f;FsC(un>wK1nHsZ{r0#MJbJ! z@Ks!+l)+5~%F~px_#=b`{lq7!^d6rTR&v6eI zu|rG!3%we$cQB}-$p0zj4z-?`{%^&Ocvj_S6F%mngO&(F8Ox zYNslIB}1?_GO7*0S|_-Tk1+&8QtO7aN5$KMf$6w`?Xer0gW;JChPN5+h9F5tdMNl> ztJj&~;YdF?Bw;Ke%g+IR4)Sw|pYhu`#m7-TUgc>b+I09CoZT?;SjgG@n@lB5CV#d6{r%H!uEX4e}LFv2vyogu$ T)=vau0zYIP{fIgEGZ_B?nlG=O literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/AnswerGenerator.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/AnswerGenerator.class new file mode 100644 index 0000000000000000000000000000000000000000..d7bd413463a1b0fc7335f2ab8dcbdfdc5cccdab4 GIT binary patch literal 2584 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 Mr)|(SYV8#MU!T>nTmS$7 literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/TripletExtractor.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/llm/TripletExtractor.class new file mode 100644 index 0000000000000000000000000000000000000000..c5ad06c374f29de2d67558697075ec1a14ce0014 GIT binary patch literal 7647 zcmcIp33wdWUH?6;q*<-Uj=iyytYgJv*-d0w)+UadLvjtOBH4;1TUfGO*>#iA?r1gE z?96s&R>&Ft>1v{D0n zeEuZOd+&eW@A;Eodf_DigJORQEl6l+)zOA_f$f*gMKkM|ZXtVS_Og`=1lo_;t{of~ zNOT{Z?m!Y98d5s8Ko{uEdByAlmlvGuB4NF9p=_4s%Vr_#IK}K#*)BO&FnlE_oAOXV z_ez#KXb(BI<&tvG*k{3)gA5UdIi{H0V1Slx?>_eEuzxS@*%Qx-r5-g?*!rJ?IqBY=5{|3YL{& zE^NVG7#jBJ=)!)1Z3?v#*iLrL_Ni-&Hz$y;(ySc}B=I`3toT+riCY9-nzF70{l=g( zYn20I*mnKEvRz}z^o?1s>>B(&=M;O56IQusy32BX+g*3w-DjM%jJ&mIIka%z2<9#M z907>10sJD+wlOxSSPuZeJ1y1v*UMr_QDuBymWHw?5cKi^@pwyZVib z7rWLd*VSuu#q^WQxQbnudX3kDBh9cOY|S*1`bO3Xu{S&=W~1FCt;lp6GG3}0vdVZf zTh;~G6pCzZ-*CK~8PE&1D@oT}&~@q3LtAhdeHyYd7H<{UT93tXvm`Ln9SiI*%Lo2< zJ5h$HXeQ|anFL29*V_dSG~p75mubQ1f4yjV*Nj&&%(7*eu3=p%$-rN5y(P!W7c4_n z6l1nxJ9(?zXArb(1g5`W&;)@;cvW0t2-R3K=E`1Cg>S)Lv|J+~XkRKdXhZ-;&U0m$ z`b?4j)L~ zZ}b~e%)Bt)NPXTe8M9WfWRblelBbS&!&97y7#d%)^cZ&Kh;J%&qGIPQ$965hKXn_^ zGE&lX9HVHNE~S{OI1POKy1G)))R8{plx3Adiniq|p>5xyB?EpJWjb1^+xv`j+{-zZ zS?)Fbl9jXP?3_`m>f@)5*16A8M(H2N&e?&|!zLNEh->VpUQZm?uh5}2Ur6uHu?bYD z!m?rJa+Na8Wz3pBBiN&JWWkbhr_NeIg>`OO`nhcRC7O|e;TxuL@8p@&k?D*jo3fZp z7SOcuGSpBX3&EOjoc;l;=k^lDYj-iYj_zBHTSojUHq-2&Ga%>`?S zzBYsNWXCU6(|m!O+Nv(ip&7^57~H6=s1Z{wn4{Z`%I5< z49NP<+|kR~F|Sat%FOap0-aN#uc|3aWQK&zEbliSd?Zl2L{y*MPj&B6xqU&$MZB47 zvKQFZJsNjuR3sUE5h9@eaXXtGz4579$5L? z%u>nWz_Paiey-x?q%X50(Ff~z8NP-u{R5 zTDs-yb$kOJrdw1*24>z2Oo1H@{AJ%u;vE9XYB7@S_YocM#JgyqQiZ`(HBdYjV~HCD zR}&$U_$GnF!(pJXR90E2K`ig(m^s-8ACd`FJ4)eO@E#4{s^h)*HVRu$+EF*Kn2xl{ zqUltuGaN{-YmD*;f+n26x9j*0d?&NScIP}+uO?Q+mwhx;Q_kz} z)A3#SZkkN?Xn7=XXA}A{@pO5rhlkB;xf_i^Z^n+APJZ%}pvfov0^2iM&T zY6!e#JXI}oD(4g#8FVQ;i9`w?1l9YHK&F{`3RuGYfGi|GC}2qAHiH~?ELk8J{y&T# z(eR^E{2ycZZvxBu$*5}vpx7!>&*=EDEH*M)2mMLLid)d|5rNl9yk@twuwX?6CxvJ6 zoV*6E2;AMoa4~O$wBti#v=i2+t2$Qk0)yYo=Vc|0VOB%^LJ~j0-ZP>afE?shSE>ea zt@DSi;aR+-<0q@FAsW=AxId-ir{%UzjcY@gJos51KPL}5co4Fb75)=)H2wKCeKnG3 zy^QO3;)P6&uPJ;Izo_9;I(`Yi%sRQYJ&mY)F9T7^5jI15BW{msT(89(U^twua11S4 zqwb>Z+p~@}=yFWtO^$J!&IIqTPJ5Gr-sMxn>c%Be1iQl9n&H5 z5P_}CrK*M})=)kcTeImzOVv^~%*W#c$5mJaW^REvk?lGr?SgA^&ZczZ z@o21Oag39U^J5zts-b`=UOS_yW`vc!ItkHC`y)1WJ6%|pO)MB}X>2uLhFz5`HQQ1) zmm(*ViLm*@L9~Np)Ck5s-JkcCCdyucPLUuNSls>(>fNypw?4CkrmFYb$eN)K`qv?D zUX*J}N(U~jwceNWNDOS>`-(qjFgMsjc2p8RwT( zgWuB>D5}1!LTp#+jY#z~GN!*OPC%D+I%aV;ZysnCSO@sL!CtkwDWd?XP7n1EWH>MZ zZ+VUAOzdMhUdq*5Xljxd)SNZK`wKICZJp_pLBQJZM$Zd;4*8{VE1384eo}N$GkFo{ zH^g?aWzAJGGDedr=bCo0m3IfRjc=}kn1UNSQX(y`)x=KTSH&(i(|Y9D?xMF~$r}Lc zFv~r!u(ek7cs$`Fz)-xCe4AiRJ22*X3zbrn?jDA)syGdZQ!H9dz?+SS>q!jpNnp|r ztO2TYeM;OQGMd<}iyOrrfv$Bbjj33myrz6k-~%UXKrz1h)c?PFo9fOLg+ z57^c7JVa0LbI^KT#MYVTam{ns{$U=p;CJ{tjaL5dWhu`Ol zWbg<0Lz0$Xl5GpWdA;Ue$?P-4mvl}Y`Z%^8TEWg0?0y2;RowJU`at^Tba%SvDtfQt zw(*{iLQ5a*J@f+Z09Md{y65l;zVeyzXEBn#w|50&t2mQ@L?nYW?&KTMJtQqfy_o`n zc9FZgx!=jZ`_PXg7~tv{?#3H%f^R@l{G*(&_u+c{5&oDW9-+nmgtki%CXGMEpK*`E z)|5MiKUbFh3-0RV8)ANjP=CptBof;amPR@LimMj3@tN>&er>{;+rRDT0>syyG;@#W4TzRAb2<- zo_;kr^bExcO?N~E$`F6w!~c&N#(s>Thaq?egKz-%^6M1eYQ}h<8ppfo)%WsZD$RJ3 zs@(t|e}}&(rTv)4J7~~0?hoM~_|;A$ya)e?e^Sx%Xw9IH;Z^*R1h-YUqS|*w4cpe{J z#q%vV|8N_f@XkzY7~3y4#v{2MxI1Uqp3KdUu&ud3`4 z%E>Z+Lio=SUOKcJZLgqH!($pg_zJdY*h}a7bndHU(xM@$k(G$$*Y=d`zN8~dOF#L` zK-%83f{*d%W&ZrkReW3qcUZ#O)%mE>S#l?=Xc4mZB}FTB3+e1rCqPF!c@@9#5sb(h tC{$qy3G6^Zv`M0(ox;e<*dn%5j-y?4)^^E=Ob&i&`#SAPSzi%JSH^k|6d=tY7d zz0VK1VR3uc*evafvSdiinzkwD8G0tNJAFu^PeV$_ThJLkEju;i=l!Z>91^cn->vh5 zy*l4DYEDI1#yzLps0mwU!p%a%v?`*`5Hl+bLxm%4MOioP-Mqpd&@rgM<5K)272%wY zA)IFzs0qm{T=L8zw;F4r$@2vWgxr3ZCI$5jui$xToxjN_VycXhmn48x7nMS$U4rXrs5h9xthVMLqAM)WEV z6#5Mv?_(k=5$dOqwMclDDv_K@-z3BGL}y5kqco!yF~I}O?xgSmZfY=ee29-)io#D5 zgXU#m^C<-&s?x8SeBhN=MnPhSsN6o*@d<7-T&(e`Saj?%mk&(2M>|(?Te=KSqF{mK zarQ^iJ9)a8z;Jo1VN0_nR_#O6HA|MbYuk?G(j*I1Ia*Gw833<8nu$BZ*wwS zS?iR!wZrSC`VNS3xo46mcm78~cpTf$CFv`4$w2na;gUziz8WAm>+TG&BdyLqI|u{d zv?)1dj?Q38^5}4`MV0$U>CGeOwu7C%YR=$IZ%K7%h8*>olZ!O0A*z}FqU7Z&od~ZA zH57>Cb@njT8aAls9+6aR7?RQn+sSa))}n`+Aysr5^|DwtRl)a%8gD8f65kN6TyYdq zdckp|D{1(w3%Tc1+$44w)|vw0CKx{xW@U~|jjQpZ*04nVS>XL?nGSO-JD9+?DLlj@ z4Ubh5d%}=8nq8)S=v0N_JLC7YWv<5IGlpM+GiQ($W ztaOp^J;gN|#4#EN33}5l0(6b=z8F5EHKvAt2aQI02aWCo#C^w;nQp_Nx!u7}lfTJ7 z)55P223>#XZ=QArNis#ry#V{egP)~$!Xpk~j`qqxB{GlCX^ooC$fYj=pggV0Q7t$5 zoL;}vHimYn5uYW1BIYhJq2zQ2?LReWXHXek{}#~Wxx5uvsw+#=x%hJod&oVnf>rWQrS><< zVh^pia(^OSpx5xP&|cylwH;lj*O>Qxef=+tKcr8Mp8m=?cl$0us?*h}NjbsNBH*O4a(#9sG7ocltV{a_)y3)!t zrQD%}%P_+S28J2Fk{Ko+phMD5nPK2dnc+84%Jc57q?IfOl}zk?_dU;f&U-uWIqQG@ z=YziixQJgE=u;TEWgS|%y6;qSSFGCZhINpJf@VTTLLss2xQ>58p?`YjhJmEQSPOr# zTD5K$otmG90nNY(g>xluKlj$Hy-M!TF8N+{r)nMSR;``fzE`#@x#zr6ecyKdY(uzI zcPeGOnnoI03WFFjFl=H3qY6*-(nmJGp`8v2@_eIQP6j6f1NfzGCdQ6MpmbB7Sjf1Ow0=LaLcWb zi#f4np_(wxn^+J=gN$4BP;@yHpT*}CPEfbebaJGzR?|(ve%{1Wcsj&xH9Z||!$!WI z#WNFl_cU#~JyPlskSg1`JwtD>U0P*6A@nvh+6_U(1|(5X2jyXd-}Z}|?hB73mn?QeT~ zx#w-yu3ElbrWJ*@#XhMI#&*~s6!PSGxbKag(%D>S#AwkgS(O`B)sYB9VbJ_thgMJb zNJ|>M7H-_OEgn_g%ncSg$7LIGLs4pNzR{>s8|g0yc%t2=+XoH1p6x*Qm>uDiWn24r zEKU?`W5FzUYJ0CKnXbI{W*ZeNgX8(Tc9lVpux6zvCj(6&rUIojVTE+44qpa>fyS0n z7z_tniV)D+RS}@27})f!(jKcgN~`|D_4SR*G<2PtBQv5(UZqqi?+Ob)KH2?blAnGyW9m{>PJf=6jdbMP)InogZ8hd9^jvLm| zRlCOem7XCd-zCrUYd(*1mh`Syt|jpug~i64X{WrR=1)s#<=IGGpo`9w6*V)I!1vPl zK7L@}htk@Aq>yc$ZH{~B?b*@E9d`RQOD+(%6@D9!U<3>exnjBHie1YVJ#VjmP&h6> zK@Qs{ZgIDDfxjAKi0V3iG(;4uR;9A(_%<7Yx$d<yZjB&1Rs68X<|UH3se|oH^oU zH{%WbOyRMILs`$Er+A!4&siRl8v5k2M5#~iIl+_H8(!eP9LPoLd5>wnZxEf9^9=pC zO2lc7%fIAbptlXW4S>?AySEMa@J6<)?Gk*j$=CFhCRx%(LSb4Sny0>+6D z5d}?ZL268OgzwevoMXLmO1*Y+zJ{+wj!We>?VJ$K{#bI4vooyyuM-_6KEca=k*kDZ z{ziufufyuL+GMY*g*z+0+7vdLt8I6z#_K#iV#TYs`8+`z-<_NN19a`)+&?h*JLvuQ z=KhYsjrrLJcr19O@R_Ug{FT=h{)rPA?L&;*g}IQ?9^lCaVlJ-}GM7(ebipJ(#OPfN zWb{lT23pJ;1TE&18ACwH2xMfEG0;*zMbJ_{okzapy(3@txyo(ab zjKes751SjWk9+o)xJg|>`UnE)@rZh(-A4wsldWTPgx`W}uvbGYWb85J-%VZ{p=kCH-cz|=S zi+(Pz$v{SnMv{`^aA+~F2SdzmFe#bQ8$(O^L@<-!l>4+peY zXQ1Dp)W^WyWZ)%DPcSJpN*X`vmf%y;*+fpFPAL(D|Bpz1Oa(vt2bE&Tq14Bm*n001 z#W?f^pn=iaRS_%^gSC*I+6Zj4gIoA61Dw*4pTlO~U!#9=fJ{khBn|vod>?r}miYL9 zHHglp8&*QtUZ$d0w&$OJI0^HQ6+VT3Z1z1oH~T&=-^TdMeOl@IUKM*70zmw?_|{1$rRikr1~f2&m&w%B{(0Bd-VM+RdS#tWE0mSJXx z_qpwIuWdhR?ueFV$SzAy>Q#oZa%F20IZRr}7jO&(hU+cWwO{RYT)R)c%5VF8ciZP} zyQ>`G+V?#z_1=8AtoNkr2%jM%9fo4#fN4|v(rZ@@_74S28{lz|cZD$=FQAAY874)y zDIACVD9CVcPfOQs$Us*u%reZ65=$N>oG`hbWVl^U#_)fZ1Fp(e9zWr12NX0l`zy(}nIML-DQBz)v>*rE$(^H_irvrw+<6x0! zNvxzLg^=O&(;ii)D;|1%8OWw9);v#Xt|jrA^0=zoR2}<)@PyB`aH>>;P1*Li?)ie@ zmyl*(m*p63-BnyyS82z1jm`nXbVGXLagQqKKjTDY@KuYuTiloCJu;5#ZAsiW8>3Wm z_*4qe0apsQv7yW=D!?ZaB@o-EXPBILwfy-w{bCnx@kj%H`1jNV}X?-_CA{ zb|qSqA-}15eoNG)sot@$qnC^yZGJ2Qy`ch{6*KEf=|IyIcqH_;a)KQGWQgX#($E|z zOJ{{$IdA&hto!Y~!Yb2QRP$KIiiK6v6nCk)4?>b&Uv-2X#vArYotxpa$M8CS1|r8W zk`3-Tt_bEEN_Bd>)ntk>%h1MWRJ0WLmofj8zK$Sj+;uml79?@up+}umb9oR5I^fCt9tP7@o{xb&8#b)MFY8MX-<&0G3%Y4Ckv z$UjRq`c2T+U+KxFoy=GkKY+a*xR>c}z(KH;!F}L>MO>!0I5iz2T#10Hw3;BT#mn#M z_J$raI1Duxx7+q|G}_(KYh{bLlFD_@z|Auj599dzaENxU+H0 ze{t#~&H>*8o=pLsz)gb6;MPzYzYlCB+@>{0WOwNL1NZ2yNWMAx4X-Y6x}zkNz-X5p)FM2&|;GoqNt!v0ijX|rbP)B0bjStm`*#HshLS#_}L$! ze?Y(VgRUiyg-e%y^*6a(?mIJ0Cl9o=E15fI&fVvnefB+*zy5jtJAkWL*ANq!tU8Ut zH|rZ#Vaup`PP5*Wn`=#3FEpH*VHK|1p6NXrfIvb=5-DD7*)RmM<#o9w3zoF&g^JfS z?RqhTGzK(ebPPfl80mJP$@r=zEw@y+ou;uMUE+*Q_X6b}Xc+DQxV^g0>{Nge9s7|L z81$U7^R>|oP)4V7y)YS!Vobxhj)OQPu;0(8<(XC?fOA>QnsnC$#-|@fwg*p(xsrxg z1kUe;pvi!zYc12N8O;nPa74#Z91}>*o3`m)7Kl&hRuqpXbevQ?#>|?!J*{IBQvw4< zW7VkD$Ri66lJQe5o32M@1zy!LtqM=p4X;#Fmb{J`WzlF^W>b{ytd4Ui2Y9@dgpLq}4KRe<^S#+KwF}BHV9~N40tXv%!&q?as`T!e-Wpe~ zCvA`H-im^SJA1KuEq!}Agd=3BV%BZxwVG7U=`NP$BS4FmBfa9~BKZ#_*Cn)_${tVx z3lzG*zOrc>%PmsYyen5NTC!!QDymCm4)Hs}Y`gbMMX?!AZGT1R~)-H+J6KeXZYkOQ=61jaTe3rrI z_(FqJhjNu;eRuep_Lj3@ghM(wr;AdJ`bPraMHvbmgV;BvU9${#vg|k;t<7TOZ1o=G zj*WNOvp(+q25ba0gjkT4RWUt-0@O=3)wp0u*EPt^P{)MTz*#lbQ)9o>HE_Tm`)^l{ ziJ(r7W`^Q$izBASG*>b8+ViiR(|r1lzn+86brJLYzC_En^o#R4nV^TZK+o=yCQq5E+a{|WY0p5cIsAM@jai3RpTqp2=t29@i^79Z?-l;P%!Mhp;V4w~Y G6aNCfWr4B) literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/EvictionResult$EvictionResultBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/EvictionResult$EvictionResultBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..301be017b4b4411b479213a0b9de8e16ab612863 GIT binary patch literal 2321 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 K_#QukyF0rqDXmFh?s=Z;x$f8J zexAuc|NF*Y0bIaqI(ifg+%|X2Qr)+m(uHc(++DD1ei{l?0~!(v66b8!_Gc9Ij*eZ| zkyJ3X=53W;xV`C=cC0nutFBkg?TxCrUfS|1mQ%WF)@tUuRfwJ!>$X#|s%hv@Q^>&3 z(Py9^M--es6p?}+yP_bs5E$y1?s{p(uiEbVw9p+jkP|M|x1RT9;Fy6y3@J!iu5bIh z^Oc%{Y`8XXQv3^6K4c&-z)aP0OyBlgLWSUjfs-M@)~Z#hP*Iwrj~Mtch7}~&O!v}r zb<y|%H+mDTo#h{V(X^h~Ej!^?+LY!^67jiN5 zmME$TMk3i@#a9}{#x(aSB5W$NPwKG7s< zIX!|W415Y@I=x}mHfEXKpbF;GIEV8(W(<59PqtYex<)g1Os8&LxusyFTafk#Bgcxo zXkZqfQE+_A+_Yvrcg^%~*go~THQ#i7=FyFlMPb~}^}$9C$dD=lx@_Pn2~e(3v2K}l z$1gOCOQt_-;Bzv4tT`PkDOTc&z3!TRy~^+vLgSjLIk(@~nP~;59srwjJky^Rlp3bw z$b#)!OLZo$dd*yQsAXhd2^^s3#B!a5vt`Y@J9f?H+6%7h`N3{rxN{4Rx3%hRmM&Ya zRW*I9LZ$j@xSc!5yuDB)J7|&2+AtRa*>>tXBOEn_ABtj+88?ALwQ)PFgM8 zhHV=*Dxb0Ibcyq_skoIW#kSHwRBz36O$&Ue-T2+@h686h;a#IH6#di_+k}zg#@1`? znx^77Q^PSKQoQ!g7_}j`9?##fs`O2QT95{s3`PPm6%0zpRFDpb!tqJOYnd3L73y2jB0SEll}c-;uVoz@#@tz zYtEKNU_^)TV{*9gs9UmX{-T7bDyQN_&+}_OPwz#`-|#B6B)+R)CR#FTSI#RF!xDFS zHY-40VsQ`V8gW0bj2%hfr8K^emv#I=`uQvDd99Ppc6Yo@D>}c!7C&do9b#9(uj0{+ zfT3YenQq0gYJ~;Q+pKR#!HQo5VokJd;Wh5fF7Rh!_{O;%8;U4qO~+ZWeT$98n0MI# zXC2;bEC#N>{c5A*$LvM>oa|=1j-M)c(Kw3^P^x_Iv3==PZl7EJB^L6z8p0a|g{GH$vFe2X1V>udI z;WI6V-2cUp!Zmz>x;t#pX+vti4RPH(5mAU%mT03`sTKc(v@Gk1nV!XUju;^TH}FNi zwG;6g)rBbANp$o*iFo&lq7k=fpp$5z3sIQ1_V6llJ?lbvypwS7(1g6ybs>DXlW^!j z!kZnjdm7I~u`BZ_MU*Ix?;-t%jx1yX#-R`qWkHHdidgC3{8D$$>|r@&Lv(U}8DEJU zUx?c|Ae_CiYB|WxaC3c?=&+I!{G?cFWb^4Z6Tyggq0Ej0D+_}`HEHMHKl<8LCfI8nTZ4+XCj z9$lK?ud+J%4`lM{TR3_L#$;Z-htmy2v8)kNEGP1sU=nX3cL#lWEuV;iCd)cOljUSy z7f><+>G@;~bhex#=xjNiPYEa;fl~Q&3^Y~F5HwXb@)-dc5r|R)q~7gX8ZU(|H%s_! zRA4b!gZMjcvAOiHnfwv!9P339zrzM46_@cEY)Tr__#@n=lz@Xx{B;|~Uq|L04Cxr*zohaG9ty?Ody8$E zRpo0o%q&0g_=!ywnxs_X5O1jQEuuB!pwWAYLwjrGw_-@C{F~1tnO@CKpHt5VC2=x4 zy}^P=X2rO}J{R ztOrvpnP`}$CFfsUDQZF8p#M~5Eyg1eh+v|%QGh}uMw=C1~l zG-eIbn1`b|IdmGR#U^TrsPG{AMq36{e3NT?@GX3sPZj+3!*?hpDSeMWFXD%M%Mrn3 OvoEFaDt>~WA^$%tCIpoL literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult$QueryResultBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult$QueryResultBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..122c997716523da90ecf382e23f6e516608ed66b GIT binary patch literal 5961 zcmd5=d3O{=5dU?q4Y5NG&VV9dfFvA?2%<@dl5hk~I1&T_uSvE^hMmlW-PsKR#rwho zZ;?--@5zIQ@A(1zEPe!@&#IZ(+1c&M?mqL6e@u5zP4%z3tE#K3=C6Mq{t4hPerZ7+ z>Jw;?Xhf4h`xPT^BrU_9NuHXzqNZJera{v--64Vcp5AjS(2Nxcv`9P#DKI$g%q6d1 zNn6Q0@j98Aj4?l(F=mo;PD)wHGdY!6oKV@E<#tEL!#UGRsfDz8$fjcnGKDF8Fi;}TCW${L-AkeK61iOr0%KIE8C zmf@O?9juR;wn{w3Fl%F&0-S9U+r8DOYx9PkQmGi29*JIWH9Aj#vQuJLu&0b+r(;p} zNF;+jmGcBBPfP5>GXl-o+>~eAQd{{h;%WJS#Ir1K<-Df4=OmtIF*5uVpbtn4;*daF zpbW!0qFlqY1d?Nw9c#ijRAGX*f)^xS#9`WW*~N}Mf))7*^N&PkjvW%D&3@ik_}kV2Z@RNI%DRT_ zW(EF^f(0{|vP~5I|IZVn5;`6eIl5Qo)CoIpX3Z%}9ky-9^&>gQKg*e$a?;7;$|h^N zDm5UmV$z(k4L6seOQ^fdg$8vs4AGQ^5xOEN_KlggI+>fBQkk;`$zlP{v|*hyGA6$V z#0GcPBuflc@tH^ziMen|>O_nwdzTB^S{9{F2SSSHblD=-mMUd&zMz;?xvW@qFI#?x z7EsAhAuWua6y>x~Ni;1kmKh>Epp}D7RqHkvBCCMYQ^l&~k!#s1vZ_mr+_cLUXIB$f z9zUz-qpETnr#NjD*iCnE&32+A*E;DM)9G0yvo59LRKm9KG6rPCUH|<~)KWXQq_^FV1GJ3(gi(iAK z6!JiS2}LjC_tGrxkmzk|!dET$8n+YphOfSFDP$MR57W*&X_fS?;opYG3@&Y`Ot}*c zo&lq;;!#S}Eh-nr94DQd50Z$e0V8)n$;7i1$zs?qMfk(upe=I5u&hbbRpeyygiW{6 zh(*b_qI;rKH*f+!3T)Fb;?|$Q&jOn&vr<*&Zx&mqtf`|sqLW%G3L!8{Z%x#j)Yowd zr_rb&(`Z!J5%(2uPPz<(N-vF{O135Wsm9XysW@AbpNc7spNg<0`KfHu_^I4llAnqw zjh|{FjYcKZk{DDfY5Y|1Xf!Hb%4lt*Q>yL>*`iUBz6z%F-G}(iQ}-OTY%q|iY_Ihg z;9#EKqUIE2;;RAB0QGG6MBmPP)ci`rI+R1L^;rTaVvg|<%7WrSTWbc@olGEuEb6^2 zPXsHKywdi*hI?4;A=fXlTp2D`63Qylj2mi&DQTkkj+!gePCj1ddX~AdW|?_SX1;>V zg?O2pSmu_RWiDtk7b?iS7B91#W$vh1<~2>`wF)v9<7M`-%-uE1T-0PPR*<<5*U5MI z*pzttUQb*t-maf~fgAA~+0Pp}So211XdAgvVIzZhJ8mQWHE%=@KZ5?Zyb}jHR5Pd^ zzXbh!xfusKTr;R100rK~dp@X8SV=($xZU?V{V$|u^<5+$;200rk5jYJdmrQBrjyic z@!n7Iu)Dv3+8uY%`~VZ)xUavFD7!t%E8cj2e-lv-dX!iDoBqJ@3-q3#r*-G9-CYe` zJYjDaGxgImM9=VjT;k~2poODRf2lz@YQ!!6`$@rP4Y{R%|81i{#5Y?#{eHW^KMo0H zl>V#mZPZ9VUJmeYISTF^z=o*zF*tzv7->?AkC6^B(ji7V#7NWJ_X%S=njWD&fe#*` zEz)*)<6>JD7C*wrflY6E*#K~s_U$Q!`t}ESgSz#8x5@9i{jSgN_WIp^zw7tAA-@}@ z?jce@{0+p}2g!@M%o_0teW}BzC9D0+qaDZR)Hl=IFX_33@92#)oMzJP_gH}+@DuK! F>tCjVtd;-( literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/QueryResult.class new file mode 100644 index 0000000000000000000000000000000000000000..4ee4c036cd2a91e5c1704442b3e599693d3ec9b2 GIT binary patch literal 10596 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 literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RerankResult$RerankResultBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RerankResult$RerankResultBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..8b51762e5a1bf83ae2e8aafeee975eaf7f2adb3d GIT binary patch literal 2533 zcmb_e>uwuG6#mAStYbF!OA}g3N}XamAscQ5;>5HuqzTvw*dd6^pRql0HeT;W-myh_ zl8UDQiKypNheelpBvb5S1^+f5yBDyo|=)%J{2qPJAu-eS0&jRHmI zxsx<9Sk-Vx$J@vbq`D@%rrl!DyvQG>aI9LX}VmZ1t9WjlwJyQC`Oy)+r+$-WDat zZgBanDbMK5mE4x(=Eq^MK+`ubj5PwD(pT--((H%>yKlN?-4ge0+mT+SsQ8sFr&D*@ z#sgtfsZkjf7{+U6%jUAzr4q_SqOd(oTO^f4iOQ8>s%+Zgu-B=J?lC7WMc_2Jb;7%* zng@#sd1ey%z4Fy7VN~%G@7&0$s1D^a_ur`&2R(Usap}!zlx<{;{s#*dqRx6n%#f_B zX27sPhvDiGrRYu6ByY4U{KCtNhEEwL2RjBsN;;RtJ%4%F!bQiBt~tGKL+qI<-!tJR zwV}WW;!wD9-*Kt6Oz%35bR{*pijZec(@o(4!;b?>;YrZuvQf`pG`StNz7pLGHK-ky zn;OGG8eiZ`4P|xEDpb_}_Gr`YJ8fb3F8XJ0kE=%fkl|7I)CGdR+56mXTEfkg9jD#9 zC=8#8(8_?~F_p~-@gG9+{;e_4D*}iTx2&2e1!Yb@u<5*(Ebh93PSV_nm}&T$VRgvU zQ4VORQLlWpC|zT|x41=3KSpgUK_lHHV0edSWAxmhXH4B|G#cLfW@L|UiXnNrWnLnm zBn-M#Y4=@vGf0!EmHZR1-#qyDXjH@?i1)qG6Tk=fkY-`C81CXD#66%Y0V)Ud{Mut^ z`NU&P zut$`lI9Zy{{|>E8!^AJpp5mH%ovF|;@6F$+{DGzK*4Ce3MMWVo6onNZC5S>2t6qv3 z7U<_EPsKyU%HLD*@b@-pZHM+I5qpkl4aMh}qA?Psd-NIQr?^N@mBD#s@l)JZhSK91 za)7ceHe{R12FZ`ecoMswMrnZUGjDAPpVKo%y8HCs!y(OP2|Yz01VoZw$4!AjQXwP3keD_s!<}V_kB+S=NHWZp?ajhB8+Eg=t(RT9 zQEg~jwT4zLY}yswEG+8{&8jc!PSbQpf{VGPVOI1;3JRnSbV60orQ#5}8S)2LNr)ZY zB*S`TSvNJ;u&srP!_ZTD|#IVlo zdT5TRc#9htiZCD`XECDU1Wppe3~be#xyFWPjp6s3%o}&OSNb zC&KNu46oA0)=0eF@`J6G^;2Q-Nb`3G_VRSh9qB!kZakX-NQQHzM%Qu%77B4ff1*+(V*Zmm!qstU%#(nB{RWw^G~irs9K^(zLihTdRHKg~nJ(7B{L?xN0XhIisQ z+jbq7UWG;7t=SbPi7y$ZgZD-w>U)Mwh_BuKoK3Jiu5dpwPDKtY}Q;_F2zGktGyjGAed zx_gYi=>?|u{=B!kKx=w21M4oNcymS^QzVh2bN-e58SM5G#DAbULy`U_XarQDXBsnN zZDSj;$fZj_ViMRuv0Ol}H zE1#5hXBdB?g)>2gJz<4?2Ud6qmxaO-LE;Q2^5c(@`jKYw0K`sD4AZLwgu7HzHPpw|5S2wF?O#u|OhN+yxqR3amDnZ$FXAEGNG zXA&(T=}{zm*L)1S?A5Sg#bD9OKZNI~Zd3@XUdPm;aBkU#BUZQM)zv!-B!$A?E+<}`4q!CVXmTHb{!6F?5N zJ-z9(piucIjWTJP>M2f3GailEo??wiO!kaFgfh8<aU8}cG?P4fXnaW<64ApLQ3A$ZlF+MljBgA; zZV9wxr1mWm3wgbUTf*yE8hOq3bBCYe6!(vYXP5-SCF%3(*Lc71r=3mupGWAO5qkUb zPw;mBDc+%iq~Y9Sc$E?iS686Y`}R@$Df!K-z#z488oNEUyvp+vLS?Yj4|ytczUXcS zbc<4_>t36VftR7*5cnBSD*uc(a=-jX_lnfJ^K9u_i2?T P2?`0S=s*n{Fp>Ee{ksuG literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalDetail$RetrievalDetailBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/RetrievalDetail$RetrievalDetailBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..9cb3facb7ea94e852d19b058647383e6c5a84e6f GIT binary patch literal 4158 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 O&tRHTLWpJ&C+k0M{JvBG literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet$TripletBuilder.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet$TripletBuilder.class new file mode 100644 index 0000000000000000000000000000000000000000..b5c2f004940f98cfc623a381e2b6b4c7adb2e350 GIT binary patch literal 1840 zcmbVN?M@Rx6g^X*Ep>rf5JVI~LED0?ABbRq1V|7}#Y70k_-orv=+Ny>vpXfhC-E^f z!H{6$1NczJJKa?ZyCDrfc0O+JoO|z?bEm)moc#i@hC&K4bS2Pjpa*e=^r3ZRnYQH| znD0x6ysQ}F%fbqqy4HbNmlbZC zd#-5MTulY@dQ;dH?lL62W&oZko(J4ju5bvXkxi6zlOLx#Q!`F5J1&)47 zTb5I?xi?jmves-A!o{{(E*#uDZtw{A&u#vGyBFFS3?Mcv+ujw56WPYLLqglIEzjem zn*NKVB=CwFGE`(#?g=b0j9=|ajqVqUNoxKWHD4Ev^zMM+F74tp-=jIE--?ipUW!Y$ zIQh~eNB-lqGU->QE%{Th?=6`7G-^;#kO>+!fIc#b2Q;^bWaRNM04mU|lS|}he$eoZ zmN8t08uncRC~}UdgL*a^w69~(FcH-D(V*#$LBmXvlrc>eX&zUJAWhTIPYiy_pAZ8l z=%X)vid)fK__Pj1()tLG1Kef0ZH=30$2`Mr;40Ki1ZoemtvktGxWatPHi#LTlN4!= XzFExch?GH+{xDvm7YkU#YmEK{CZwNG literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/model/Triplet.class new file mode 100644 index 0000000000000000000000000000000000000000..e8f41936641cf5e5da27d17011cd85855d417e29 GIT binary patch literal 2825 zcma)8YjYGu6g|DKNhXsA%M#ug$%E`Bu&Ag&0D&kF+yJsM7(iu`bR|P3GjV4&ioZnu zfPCSDR!Ok1wDhaL$+A3mW=Qr`l1j~V_w75U&%LMb-TeLUt3Lo-f!&Q1(grdXvdAfn zF8S-_?;o$ZS+YYd)*cI%SaW{#b)FphEc9bQVgI_lrl)<6uJ@d9m9rqU zy)aO?Io^K6ZY;%iClh(>HBhjy4}%H=t<-7K-_&h4m|5}snx3`;t+21d`NjJN4m1JW zjv|r+4p}&iBMLpCU-7@ywHT!^-jUBSyk%g>!rM5muqWbE4;{B0!!i2IsvWE<430l& z2q)g1D$W=fQ8=?J(MA&SuGSrQS=USqW6Z({j8l#aj^~7z6w>3xd6PPoEKEoU=86uh zvC?8bY2lQZEt>DV)>Sr6TX;t{y15Z^%R`~h#D0u%4E?*>wL{1E=Ja>GGnr}LCWZcr zEXL|FLc)RjJN3o4nw}; zd43pWiV^24uD`zMua&QBPuEyN%lyO)wk2r^FsZ)cJO!fDwm_7H%Q!NHuF#Ji70z|I z*bSE~!E3k331-!=*Ov4(M`W{-t9455FE9Qr9fY%5bY&C+SA9PWLN=0F9j^MzK^Hz# z$f_a!b)l+IOuimZddfvLIkeq1WZ_4pbx{@jbNJlEJnk9zLfXcH!pKeuJKm7MVA=QnmnC4fKvZ07B(DfUJ7hYmiQm!JrIORR~m=>9T678^gCtsFn z6Q06GwJO!$aBMa?wi!q=7*l8jGFpKK-U!5>hYmnyE6|=d0$rn;F{ASwMa5ic;sw;t zoW&`QQ({I)gR#f9&bjEWtCn=#=!|LX7E|h`6?3LDrny^8slisvo7+j;sm3i7OIw)a zQ+|ba+p96oLvuAYYs`NEm?gPpI~u>ld#yyRH%fB?pC&*LIc5l0C=n=U*QoB{s#nyH3t9y literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/storage/EmbeddingClient.class b/VectorGraphRag/target/classes/com/zjkl/vectorgraphrag/storage/EmbeddingClient.class new file mode 100644 index 0000000000000000000000000000000000000000..c8ff89a053c029f1b30da4a2f5b282fbe48fb689 GIT binary patch literal 4729 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 GDEfcJLcII{ literal 0 HcmV?d00001 diff --git a/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..56c64b5 --- /dev/null +++ b/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,43 @@ +com\zjkl\vectorgraphrag\model\RetrievalResult.class +com\zjkl\vectorgraphrag\config\VectorGraphRagSettings.class +com\zjkl\vectorgraphrag\storage\MilvusStore.class +com\zjkl\vectorgraphrag\model\Document.class +com\zjkl\vectorgraphrag\model\Passage$PassageBuilder.class +com\zjkl\vectorgraphrag\model\ExtractionResult$ExtractionResultBuilder.class +com\zjkl\vectorgraphrag\config\VectorGraphRagSettings$VectorGraphRagSettingsBuilder.class +com\zjkl\vectorgraphrag\model\EvictionResult$EvictionResultBuilder.class +com\zjkl\vectorgraphrag\model\EvictionResult.class +com\zjkl\vectorgraphrag\model\QueryResult$QueryResultBuilder.class +com\zjkl\vectorgraphrag\model\RetrievalDetail.class +com\zjkl\vectorgraphrag\graph\SubGraphEntity$SubGraphEntityBuilder.class +com\zjkl\vectorgraphrag\model\RerankResult.class +com\zjkl\vectorgraphrag\llm\LLMReranker.class +com\zjkl\vectorgraphrag\storage\EmbeddingClient.class +com\zjkl\vectorgraphrag\model\RerankResult$RerankResultBuilder.class +com\zjkl\vectorgraphrag\graph\GraphRetriever.class +com\zjkl\vectorgraphrag\graph\SubGraphRelation.class +com\zjkl\vectorgraphrag\model\RetrievalResult$RetrievalResultBuilder.class +com\zjkl\vectorgraphrag\model\ExtractionResult.class +com\zjkl\vectorgraphrag\model\QueryResult.class +com\zjkl\vectorgraphrag\graph\SubGraph.class +com\zjkl\vectorgraphrag\model\Entity$EntityBuilder.class +com\zjkl\vectorgraphrag\model\Passage.class +com\zjkl\vectorgraphrag\model\Triplet.class +com\zjkl\vectorgraphrag\model\Entity.class +com\zjkl\vectorgraphrag\graph\SubGraphPassage.class +com\zjkl\vectorgraphrag\model\Relation$RelationBuilder.class +com\zjkl\vectorgraphrag\VectorGraphRAG.class +com\zjkl\vectorgraphrag\llm\TripletExtractor.class +com\zjkl\vectorgraphrag\graph\SubGraphRelation$SubGraphRelationBuilder.class +com\zjkl\vectorgraphrag\model\RetrievalDetail$RetrievalDetailBuilder.class +com\zjkl\vectorgraphrag\model\Document$DocumentBuilder.class +com\zjkl\vectorgraphrag\model\Triplet$TripletBuilder.class +com\zjkl\vectorgraphrag\model\Relation.class +com\zjkl\vectorgraphrag\graph\GraphBuilder.class +com\zjkl\vectorgraphrag\graph\SubGraphPassage$SubGraphPassageBuilder.class +com\zjkl\vectorgraphrag\graph\Graph.class +com\zjkl\vectorgraphrag\llm\AnswerGenerator.class +com\zjkl\vectorgraphrag\graph\SubGraphEntity.class +com\zjkl\vectorgraphrag\llm\LLMCache.class +com\zjkl\vectorgraphrag\llm\OpenAiClient.class +com\zjkl\vectorgraphrag\llm\EntityExtractor.class diff --git a/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..42bd9a8 --- /dev/null +++ b/VectorGraphRag/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,28 @@ +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\config\VectorGraphRagSettings.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\Graph.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\GraphBuilder.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\GraphRetriever.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\SubGraph.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\SubGraphEntity.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\SubGraphPassage.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\graph\SubGraphRelation.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\AnswerGenerator.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\EntityExtractor.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\LLMCache.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\LLMReranker.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\OpenAiClient.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\llm\TripletExtractor.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\Document.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\Entity.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\EvictionResult.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\ExtractionResult.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\Passage.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\QueryResult.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\Relation.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\RerankResult.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\RetrievalDetail.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\RetrievalResult.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\model\Triplet.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\storage\EmbeddingClient.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\storage\MilvusStore.java +C:\Users\饶策\Desktop\langchain4j_sister_backend\VectorGraphRag\src\main\java\com\zjkl\vectorgraphrag\VectorGraphRAG.java