1414 * limitations under the License.
1515 */
1616
17- package org .springframework .ai .vectorstore ;
17+ package org .springframework .ai .vectorstore . hanadb ;
1818
1919import java .util .Collections ;
2020import java .util .List ;
3434import org .springframework .ai .observation .conventions .VectorStoreProvider ;
3535import org .springframework .ai .observation .conventions .VectorStoreSimilarityMetric ;
3636import org .springframework .ai .util .JacksonUtils ;
37+ import org .springframework .ai .vectorstore .AbstractVectorStoreBuilder ;
38+ import org .springframework .ai .vectorstore .SearchRequest ;
3739import org .springframework .ai .vectorstore .observation .AbstractObservationVectorStore ;
3840import org .springframework .ai .vectorstore .observation .VectorStoreObservationContext ;
3941import org .springframework .ai .vectorstore .observation .VectorStoreObservationConvention ;
42+ import org .springframework .util .Assert ;
4043
4144/**
4245 * The <b>SAP HANA Cloud vector engine</b> offers multiple use cases in AI scenarios.
6770 * @author Rahul Mittal
6871 * @author Christian Tzolov
6972 * @author Sebastien Deleuze
73+ * @author Soby Chacko
7074 * @see <a href=
7175 * "https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-vector-engine-guide/introduction">SAP
7276 * HANA Database Vector Engine Guide</a>
@@ -78,30 +82,71 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore {
7882
7983 private final HanaVectorRepository <? extends HanaVectorEntity > repository ;
8084
81- private final EmbeddingModel embeddingModel ;
85+ private final String tableName ;
8286
83- private final HanaCloudVectorStoreConfig config ;
87+ private final int topK ;
8488
8589 private final ObjectMapper objectMapper ;
8690
91+ /**
92+ * Creates a new HanaCloudVectorStore with basic configuration.
93+ * @param repository the HANA vector repository
94+ * @param embeddingModel the embedding model to use
95+ * @param config the vector store configuration
96+ * @deprecated Since 1.0.0-M5, use {@link #builder()} instead
97+ */
98+ @ Deprecated (since = "1.0.0-M5" , forRemoval = true )
8799 public HanaCloudVectorStore (HanaVectorRepository <? extends HanaVectorEntity > repository ,
88100 EmbeddingModel embeddingModel , HanaCloudVectorStoreConfig config ) {
89-
90101 this (repository , embeddingModel , config , ObservationRegistry .NOOP , null );
91102 }
92103
104+ /**
105+ * Creates a new HanaCloudVectorStore with observation configuration.
106+ * @param repository the HANA vector repository
107+ * @param embeddingModel the embedding model to use
108+ * @param config the vector store configuration
109+ * @param observationRegistry the observation registry
110+ * @param customObservationConvention the custom observation convention
111+ * @deprecated Since 1.0.0-M5, use {@link #builder()} instead
112+ */
113+ @ Deprecated (since = "1.0.0-M5" , forRemoval = true )
93114 public HanaCloudVectorStore (HanaVectorRepository <? extends HanaVectorEntity > repository ,
94115 EmbeddingModel embeddingModel , HanaCloudVectorStoreConfig config , ObservationRegistry observationRegistry ,
95116 VectorStoreObservationConvention customObservationConvention ) {
96117
97- super (observationRegistry , customObservationConvention );
118+ this (builder ().repository (repository )
119+ .embeddingModel (embeddingModel )
120+ .tableName (config .getTableName ())
121+ .topK (config .getTopK ())
122+ .observationRegistry (observationRegistry )
123+ .customObservationConvention (customObservationConvention ));
124+ }
125+
126+ /**
127+ * Protected constructor that accepts a builder instance. This is the preferred way to
128+ * create new HanaCloudVectorStore instances.
129+ * @param builder the configured builder instance
130+ */
131+ protected HanaCloudVectorStore (HanaCloudBuilder builder ) {
132+ super (builder );
98133
99- this .repository = repository ;
100- this .embeddingModel = embeddingModel ;
101- this .config = config ;
134+ Assert .notNull (builder .repository , "Repository must not be null" );
135+
136+ this .repository = builder .repository ;
137+ this .tableName = builder .tableName ;
138+ this .topK = builder .topK ;
102139 this .objectMapper = JsonMapper .builder ().addModules (JacksonUtils .instantiateAvailableModules ()).build ();
103140 }
104141
142+ /**
143+ * Creates a new builder for configuring and creating HanaCloudVectorStore instances.
144+ * @return a new builder instance
145+ */
146+ public static HanaCloudBuilder builder () {
147+ return new HanaCloudBuilder ();
148+ }
149+
105150 @ Override
106151 public void doAdd (List <Document > documents ) {
107152 int count = 1 ;
@@ -110,27 +155,27 @@ public void doAdd(List<Document> documents) {
110155 document .getId ());
111156 String content = document .getContent ().replaceAll ("\\ s+" , " " );
112157 String embedding = getEmbedding (document );
113- this .repository .save (this .config . getTableName () , document .getId (), embedding , content );
158+ this .repository .save (this .tableName , document .getId (), embedding , content );
114159 }
115160 logger .info ("Embeddings saved in HanaCloudVectorStore for {} documents" , count - 1 );
116161 }
117162
118163 @ Override
119164 public Optional <Boolean > doDelete (List <String > idList ) {
120- int deleteCount = this .repository .deleteEmbeddingsById (this .config . getTableName () , idList );
165+ int deleteCount = this .repository .deleteEmbeddingsById (this .tableName , idList );
121166 logger .info ("{} embeddings deleted" , deleteCount );
122167 return Optional .of (deleteCount == idList .size ());
123168 }
124169
125170 public int purgeEmbeddings () {
126- int deleteCount = this .repository .deleteAllEmbeddings (this .config . getTableName () );
171+ int deleteCount = this .repository .deleteAllEmbeddings (this .tableName );
127172 logger .info ("{} embeddings deleted" , deleteCount );
128173 return deleteCount ;
129174 }
130175
131176 @ Override
132177 public List <Document > similaritySearch (String query ) {
133- return similaritySearch (SearchRequest .query (query ).withTopK (this .config . getTopK () ));
178+ return similaritySearch (SearchRequest .query (query ).withTopK (this .topK ));
134179 }
135180
136181 @ Override
@@ -141,8 +186,8 @@ public List<Document> doSimilaritySearch(SearchRequest request) {
141186 }
142187
143188 String queryEmbedding = getEmbedding (request );
144- List <? extends HanaVectorEntity > searchResult = this .repository
145- . cosineSimilaritySearch ( this . config . getTableName (), request .getTopK (), queryEmbedding );
189+ List <? extends HanaVectorEntity > searchResult = this .repository . cosineSimilaritySearch ( this . tableName ,
190+ request .getTopK (), queryEmbedding );
146191 logger .info ("Hana cosine-similarity for query={}, with topK={} returned {} results" , request .getQuery (),
147192 request .getTopK (), searchResult .size ());
148193
@@ -175,8 +220,63 @@ public VectorStoreObservationContext.Builder createObservationContextBuilder(Str
175220
176221 return VectorStoreObservationContext .builder (VectorStoreProvider .HANA .value (), operationName )
177222 .dimensions (this .embeddingModel .dimensions ())
178- .collectionName (this .config . getTableName () )
223+ .collectionName (this .tableName )
179224 .similarityMetric (VectorStoreSimilarityMetric .COSINE .value ());
180225 }
181226
227+ /**
228+ * Builder class for creating {@link HanaCloudVectorStore} instances.
229+ * <p>
230+ * Provides a fluent API for configuring all aspects of the HANA Cloud vector store.
231+ *
232+ * @since 1.0.0
233+ */
234+ public static class HanaCloudBuilder extends AbstractVectorStoreBuilder <HanaCloudBuilder > {
235+
236+ private HanaVectorRepository <? extends HanaVectorEntity > repository ;
237+
238+ private String tableName ;
239+
240+ private int topK ;
241+
242+ /**
243+ * Sets the HANA vector repository.
244+ * @param repository the repository to use
245+ * @return the builder instance
246+ * @throws IllegalArgumentException if repository is null
247+ */
248+ public HanaCloudBuilder repository (HanaVectorRepository <? extends HanaVectorEntity > repository ) {
249+ Assert .notNull (repository , "Repository must not be null" );
250+ this .repository = repository ;
251+ return this ;
252+ }
253+
254+ /**
255+ * Sets the table name for vector storage.
256+ * @param tableName the name of the table to use
257+ * @return the builder instance
258+ */
259+ public HanaCloudBuilder tableName (String tableName ) {
260+ this .tableName = tableName ;
261+ return this ;
262+ }
263+
264+ /**
265+ * Sets the number of top results to return.
266+ * @param topK the number of results
267+ * @return the builder instance
268+ */
269+ public HanaCloudBuilder topK (int topK ) {
270+ this .topK = topK ;
271+ return this ;
272+ }
273+
274+ @ Override
275+ public HanaCloudVectorStore build () {
276+ validate ();
277+ return new HanaCloudVectorStore (this );
278+ }
279+
280+ }
281+
182282}
0 commit comments