diff --git a/pom.xml b/pom.xml
index 244b4af46a..89aaf6659e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -205,6 +205,9 @@
2.3.0
0.8.0
2.0.46
+ 1.54.0
+ 1.3.0
+ 1.14.0
11.6.1
5.17.1
4.5.1
diff --git a/vector-stores/spring-ai-azure-store/pom.xml b/vector-stores/spring-ai-azure-store/pom.xml
index 25bf7e5f11..c3435643fc 100644
--- a/vector-stores/spring-ai-azure-store/pom.xml
+++ b/vector-stores/spring-ai-azure-store/pom.xml
@@ -59,6 +59,24 @@
+
+
+ com.azure
+ azure-identity
+ ${azure-identity.version}
+
+
+
+ com.azure
+ azure-core
+ ${azure-core.version}
+
+
+
+ com.azure
+ azure-json
+ ${azure-json.version}
+
com.alibaba.fastjson2
fastjson2
diff --git a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverterTests.java b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverterTests.java
index a97c83740e..198423affd 100644
--- a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverterTests.java
+++ b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverterTests.java
@@ -44,10 +44,6 @@
*/
public class AzureAiSearchFilterExpressionConverterTests {
- private static String format(String text) {
- return text.trim().replace(" " + System.lineSeparator(), System.lineSeparator()) + System.lineSeparator();
- }
-
@Test
public void testMissingFilterName() {
@@ -79,10 +75,9 @@ public void testEQ() {
List.of(MetadataField.text("country")));
// country == "BG"
+ String expected = "meta_country eq 'BG'";
String vectorExpr = converter.convertExpression(new Expression(EQ, new Key("country"), new Value("BG")));
- assertThat(format(vectorExpr)).isEqualTo("""
- meta_country eq 'BG'
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -91,12 +86,11 @@ public void tesEqAndGte() {
List.of(MetadataField.text("genre"), MetadataField.int32("year")));
// genre == "drama" AND year >= 2020
+ String expected = "meta_genre eq 'drama' and meta_year ge 2020";
String vectorExpr = converter
.convertExpression(new Expression(AND, new Expression(EQ, new Key("genre"), new Value("drama")),
new Expression(GTE, new Key("year"), new Value(2020))));
- assertThat(format(vectorExpr)).isEqualTo("""
- meta_genre eq 'drama' and meta_year ge 2020
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -105,11 +99,10 @@ public void tesIn() {
List.of(MetadataField.text("genre")));
// genre in ["comedy", "documentary", "drama"]
+ String expected = " search.in(meta_genre, 'comedy,documentary,drama', ',')";
String vectorExpr = converter.convertExpression(
new Expression(IN, new Key("genre"), new Value(List.of("comedy", "documentary", "drama"))));
- assertThat(format(vectorExpr)).isEqualTo("""
- search.in(meta_genre, 'comedy,documentary,drama', ',')
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -118,11 +111,10 @@ public void tesNin() {
List.of(MetadataField.text("genre")));
// genre in ["comedy", "documentary", "drama"]
+ String expected = " not search.in(meta_genre, 'comedy,documentary,drama', ',')";
String vectorExpr = converter.convertExpression(
new Expression(NIN, new Key("genre"), new Value(List.of("comedy", "documentary", "drama"))));
- assertThat(format(vectorExpr)).isEqualTo("""
- not search.in(meta_genre, 'comedy,documentary,drama', ',')
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -131,13 +123,12 @@ public void testNe() {
List.of(MetadataField.text("city"), MetadataField.int64("year"), MetadataField.text("country")));
// year >= 2020 OR country == "BG" AND city != "Sofia"
+ String expected = "meta_year ge 2020 or meta_country eq 'BG' and meta_city ne 'Sofia'";
String vectorExpr = converter
.convertExpression(new Expression(OR, new Expression(GTE, new Key("year"), new Value(2020)),
new Expression(AND, new Expression(EQ, new Key("country"), new Value("BG")),
new Expression(NE, new Key("city"), new Value("Sofia")))));
- assertThat(format(vectorExpr)).isEqualTo("""
- meta_year ge 2020 or meta_country eq 'BG' and meta_city ne 'Sofia'
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -146,14 +137,13 @@ public void testGroup() {
List.of(MetadataField.text("city"), MetadataField.int64("year"), MetadataField.text("country")));
// (year >= 2020 OR country == "BG") AND city != "Sofia"
+ String expected = "(meta_year ge 2020 or meta_country eq 'BG') and meta_city ne 'Sofia'";
String vectorExpr = converter.convertExpression(new Expression(AND,
new Group(new Expression(OR, new Expression(GTE, new Key("year"), new Value(2020)),
new Expression(EQ, new Key("country"), new Value("BG")))),
new Expression(NE, new Key("city"), new Value("Sofia"))));
- assertThat(format(vectorExpr)).isEqualTo("""
- (meta_year ge 2020 or meta_country eq 'BG') and meta_city ne 'Sofia'
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -162,14 +152,13 @@ public void tesBoolean() {
List.of(MetadataField.bool("isOpen"), MetadataField.int64("year"), MetadataField.text("country")));
// isOpen == true AND year >= 2020 AND country IN ["BG", "NL", "US"]
+ String expected = "meta_isOpen eq true and meta_year ge 2020 and search.in(meta_country, 'BG,NL,US', ',')";
String vectorExpr = converter.convertExpression(new Expression(AND,
new Expression(AND, new Expression(EQ, new Key("isOpen"), new Value(true)),
new Expression(GTE, new Key("year"), new Value(2020))),
new Expression(IN, new Key("country"), new Value(List.of("BG", "NL", "US")))));
- assertThat(format(vectorExpr)).isEqualTo("""
- meta_isOpen eq true and meta_year ge 2020 and search.in(meta_country, 'BG,NL,US', ',')
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -178,13 +167,12 @@ public void testDecimal() {
List.of(MetadataField.decimal("temperature")));
// temperature >= -15.6 && temperature <= +20.13
+ String expected = "meta_temperature ge -15.6 and meta_temperature le 20.13";
String vectorExpr = converter
.convertExpression(new Expression(AND, new Expression(GTE, new Key("temperature"), new Value(-15.6)),
new Expression(LTE, new Key("temperature"), new Value(20.13))));
- assertThat(format(vectorExpr)).isEqualTo("""
- meta_temperature ge -15.6 and meta_temperature le 20.13
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
@Test
@@ -192,16 +180,13 @@ public void testComplexIdentifiers() {
FilterExpressionConverter converter = new AzureAiSearchFilterExpressionConverter(
List.of(MetadataField.text("country 1 2 3")));
+ String expected = "'meta_country 1 2 3' eq 'BG'";
String vectorExpr = converter
.convertExpression(new Expression(EQ, new Key("\"country 1 2 3\""), new Value("BG")));
- assertThat(format(vectorExpr)).isEqualTo("""
- 'meta_country 1 2 3' eq 'BG'
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
vectorExpr = converter.convertExpression(new Expression(EQ, new Key("'country 1 2 3'"), new Value("BG")));
- assertThat(format(vectorExpr)).isEqualTo("""
- 'meta_country 1 2 3' eq 'BG'
- """);
+ assertThat(vectorExpr).isEqualTo(expected);
}
}
diff --git a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java
index dc87de60fe..4b736caeed 100644
--- a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java
+++ b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java
@@ -27,6 +27,7 @@
import java.util.concurrent.TimeUnit;
import com.azure.core.credential.AzureKeyCredential;
+import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.search.documents.indexes.SearchIndexClient;
import com.azure.search.documents.indexes.SearchIndexClientBuilder;
import org.awaitility.Awaitility;
@@ -300,6 +301,14 @@ public static class Config {
@Bean
public SearchIndexClient searchIndexClient() {
+ // Only set AZURE_AI_SEARCH_TEST_KEYLESS if role-based authentication is set up correctly on the integration service
+ // https://learn.microsoft.com/azure/search/search-security-rbac
+ if (System.getenv("AZURE_AI_SEARCH_TEST_KEYLESS").equals("true")) {
+ return new SearchIndexClientBuilder().endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
+ .credential(new DefaultAzureCredentialBuilder().build())
+ .buildClient();
+ }
+
return new SearchIndexClientBuilder().endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
.credential(new AzureKeyCredential(System.getenv("AZURE_AI_SEARCH_API_KEY")))
.buildClient();