|
17 | 17 | package org.springframework.ai.vectorstore; |
18 | 18 |
|
19 | 19 | import java.util.Objects; |
| 20 | +import java.util.Map; |
20 | 21 |
|
21 | 22 | import org.springframework.ai.document.Document; |
22 | 23 | import org.springframework.ai.vectorstore.filter.Filter; |
23 | 24 | import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder; |
24 | 25 | import org.springframework.ai.vectorstore.filter.FilterExpressionTextParser; |
25 | 26 | import org.springframework.lang.Nullable; |
26 | 27 | import org.springframework.util.Assert; |
27 | | -import java.util.regex.Pattern; |
28 | | -import java.util.regex.Matcher; |
29 | 28 |
|
30 | 29 | /** |
31 | 30 | * Similarity search request. Use the {@link SearchRequest#builder()} to create the |
@@ -61,6 +60,8 @@ public class SearchRequest { |
61 | 60 | @Nullable |
62 | 61 | private Filter.Expression filterExpression; |
63 | 62 |
|
| 63 | +private static final Map<Character, String> ESCAPE_TEXT = Map.of('\\', "\\\\", '.', "\\."); |
| 64 | + |
64 | 65 | /** |
65 | 66 | * Copy an existing {@link SearchRequest.Builder} instance. |
66 | 67 | * @param originalSearchRequest {@link SearchRequest} instance to copy. |
@@ -193,7 +194,6 @@ public Builder similarityThresholdAll() { |
193 | 194 | /** |
194 | 195 | * Retrieves documents by query embedding similarity and matching the filters. |
195 | 196 | * Value of 'null' means that no metadata filters will be applied to the search. |
196 | | - * |
197 | 197 | * For example if the {@link Document#getMetadata()} schema is: |
198 | 198 | * |
199 | 199 | * <pre>{@code |
@@ -290,14 +290,24 @@ public Builder filterExpression(@Nullable String textExpression) { |
290 | 290 | } |
291 | 291 |
|
292 | 292 | private String escapeTextExpression(String expression) { |
293 | | -Pattern pattern = Pattern.compile("'([^']*)'"); |
294 | | -Matcher matcher = pattern.matcher(expression); |
295 | | -StringBuffer sb = new StringBuffer(); |
296 | | -while (matcher.find()) { |
297 | | -String content = matcher.group(1).replace("\\", "\\\\").replace(".", "\\."); |
298 | | -matcher.appendReplacement(sb, "'" + content + "'"); |
| 293 | +StringBuilder sb = new StringBuilder(expression.length() + 8); |
| 294 | +boolean inQuote = false; |
| 295 | + |
| 296 | +for (int i = 0; i < expression.length(); i++) { |
| 297 | +char ch = expression.charAt(i); |
| 298 | + |
| 299 | +if (ch == '\'') { |
| 300 | +inQuote = !inQuote; |
| 301 | +sb.append(ch); |
| 302 | +} |
| 303 | +else if (inQuote) { |
| 304 | +sb.append(ESCAPE_TEXT.getOrDefault(ch, String.valueOf(ch))); |
| 305 | +} |
| 306 | +else { |
| 307 | +sb.append(ch); |
| 308 | +} |
299 | 309 | } |
300 | | -matcher.appendTail(sb); |
| 310 | + |
301 | 311 | return sb.toString(); |
302 | 312 | } |
303 | 313 |
|
|
0 commit comments