|
7 | 7 | * AggregateHybridQuery combines text and vector search in Redis using aggregation. |
8 | 8 | * |
9 | 9 | * <p>This is the primary name for hybrid queries in RedisVL, matching the Python implementation. |
10 | | - * It extends {@link HybridQuery} which contains the full implementation. |
| 10 | + * It is a type alias for {@link HybridQuery}. |
11 | 11 | * |
12 | 12 | * <p>Ported from Python: redisvl/query/aggregate.py:57-315 (AggregateHybridQuery class) |
13 | 13 | * |
|
37 | 37 | * <p>Java equivalent: |
38 | 38 | * |
39 | 39 | * <pre> |
40 | | - * AggregateHybridQuery query = AggregateHybridQuery.builder() |
| 40 | + * HybridQuery query = AggregateHybridQuery.builder() |
41 | 41 | * .text("example text") |
42 | 42 | * .textFieldName("text_field") |
43 | 43 | * .vector(new float[]{0.1f, 0.2f, 0.3f}) |
|
48 | 48 | * .dtype("float32") |
49 | 49 | * .numResults(10) |
50 | 50 | * .returnFields(List.of("field1", "field2")) |
51 | | - * .stopwords(AggregateHybridQuery.loadDefaultStopwords("english")) |
| 51 | + * .stopwords(HybridQuery.loadDefaultStopwords("english")) |
52 | 52 | * .dialect(2) |
53 | 53 | * .build(); |
54 | 54 | * List<Map<String, Object>> results = index.query(query); |
55 | 55 | * </pre> |
56 | 56 | * |
57 | | - * <p>This class is final to prevent finalizer attacks, as it throws exceptions in constructors for |
58 | | - * input validation (SEI CERT OBJ11-J). |
59 | | - * |
60 | 57 | * @since 0.1.0 |
61 | 58 | */ |
62 | | -public final class AggregateHybridQuery extends HybridQuery { |
| 59 | +public final class AggregateHybridQuery { |
63 | 60 |
|
64 | | - // Private constructor delegates to parent |
65 | | - private AggregateHybridQuery(AggregateHybridQueryBuilder builder) { |
66 | | - super(builder.toHybridQueryBuilder()); |
| 61 | + // Private constructor to prevent instantiation |
| 62 | + private AggregateHybridQuery() { |
| 63 | + throw new UnsupportedOperationException("AggregateHybridQuery is a type alias for HybridQuery"); |
67 | 64 | } |
68 | 65 |
|
69 | 66 | /** |
70 | | - * Create a new builder for AggregateHybridQuery. |
| 67 | + * Create a new builder for AggregateHybridQuery (delegates to HybridQuery.builder()). |
71 | 68 | * |
72 | | - * @return A new AggregateHybridQueryBuilder instance |
| 69 | + * @return A new HybridQuery.HybridQueryBuilder instance |
73 | 70 | */ |
74 | | - public static AggregateHybridQueryBuilder builder() { |
75 | | - return new AggregateHybridQueryBuilder(); |
| 71 | + public static HybridQuery.HybridQueryBuilder builder() { |
| 72 | + return HybridQuery.builder(); |
76 | 73 | } |
77 | 74 |
|
78 | | - /** Builder for creating AggregateHybridQuery instances with fluent API. */ |
79 | | - public static class AggregateHybridQueryBuilder { |
80 | | - private String text; |
81 | | - private String textFieldName; |
82 | | - private float[] vector; |
83 | | - private String vectorFieldName; |
84 | | - private String textScorer = "BM25STD"; |
85 | | - private Object filterExpression; |
86 | | - private float alpha = 0.7f; |
87 | | - private String dtype = "float32"; |
88 | | - private int numResults = 10; |
89 | | - private List<String> returnFields = List.of(); |
90 | | - private Set<String> stopwords = loadDefaultStopwords("english"); |
91 | | - private int dialect = 2; |
92 | | - |
93 | | - /** Package-private constructor used by builder() method. */ |
94 | | - AggregateHybridQueryBuilder() {} |
95 | | - |
96 | | - /** |
97 | | - * Set the text query string. |
98 | | - * |
99 | | - * @param text The text to search for |
100 | | - * @return This builder for chaining |
101 | | - */ |
102 | | - public AggregateHybridQueryBuilder text(String text) { |
103 | | - this.text = text; |
104 | | - return this; |
105 | | - } |
106 | | - |
107 | | - /** |
108 | | - * Set the name of the text field to search. |
109 | | - * |
110 | | - * @param textFieldName The field name containing text data |
111 | | - * @return This builder for chaining |
112 | | - */ |
113 | | - public AggregateHybridQueryBuilder textFieldName(String textFieldName) { |
114 | | - this.textFieldName = textFieldName; |
115 | | - return this; |
116 | | - } |
117 | | - |
118 | | - /** |
119 | | - * Set the query vector for similarity search. Makes a defensive copy. |
120 | | - * |
121 | | - * @param vector The embedding vector to search with |
122 | | - * @return This builder for chaining |
123 | | - */ |
124 | | - public AggregateHybridQueryBuilder vector(float[] vector) { |
125 | | - this.vector = vector != null ? vector.clone() : null; |
126 | | - return this; |
127 | | - } |
128 | | - |
129 | | - /** |
130 | | - * Set the name of the vector field to search. |
131 | | - * |
132 | | - * @param vectorFieldName The field name containing vector data |
133 | | - * @return This builder for chaining |
134 | | - */ |
135 | | - public AggregateHybridQueryBuilder vectorFieldName(String vectorFieldName) { |
136 | | - this.vectorFieldName = vectorFieldName; |
137 | | - return this; |
138 | | - } |
139 | | - |
140 | | - /** |
141 | | - * Set the scoring algorithm for text search. |
142 | | - * |
143 | | - * @param textScorer The text scorer (e.g., "BM25", "TFIDF") |
144 | | - * @return This builder for chaining |
145 | | - */ |
146 | | - public AggregateHybridQueryBuilder textScorer(String textScorer) { |
147 | | - this.textScorer = textScorer; |
148 | | - return this; |
149 | | - } |
150 | | - |
151 | | - /** |
152 | | - * Set an additional filter expression for the query using a Filter object. |
153 | | - * |
154 | | - * @param filterExpression The filter to apply |
155 | | - * @return This builder for chaining |
156 | | - */ |
157 | | - public AggregateHybridQueryBuilder filterExpression(Filter filterExpression) { |
158 | | - this.filterExpression = filterExpression; |
159 | | - return this; |
160 | | - } |
161 | | - |
162 | | - /** |
163 | | - * Set an additional filter expression for the query using a raw Redis query string. |
164 | | - * |
165 | | - * @param filterExpression The raw Redis filter string |
166 | | - * @return This builder for chaining |
167 | | - */ |
168 | | - public AggregateHybridQueryBuilder filterExpression(String filterExpression) { |
169 | | - this.filterExpression = filterExpression; |
170 | | - return this; |
171 | | - } |
172 | | - |
173 | | - /** |
174 | | - * Set the weight for combining text and vector scores. |
175 | | - * |
176 | | - * @param alpha Weight between 0.0 (text only) and 1.0 (vector only), default 0.7 |
177 | | - * @return This builder for chaining |
178 | | - */ |
179 | | - public AggregateHybridQueryBuilder alpha(float alpha) { |
180 | | - this.alpha = alpha; |
181 | | - return this; |
182 | | - } |
183 | | - |
184 | | - /** |
185 | | - * Set the data type for vector storage. |
186 | | - * |
187 | | - * @param dtype The data type (e.g., "float32", "float64") |
188 | | - * @return This builder for chaining |
189 | | - */ |
190 | | - public AggregateHybridQueryBuilder dtype(String dtype) { |
191 | | - this.dtype = dtype; |
192 | | - return this; |
193 | | - } |
194 | | - |
195 | | - /** |
196 | | - * Set the maximum number of results to return. |
197 | | - * |
198 | | - * @param numResults The result limit |
199 | | - * @return This builder for chaining |
200 | | - */ |
201 | | - public AggregateHybridQueryBuilder numResults(int numResults) { |
202 | | - this.numResults = numResults; |
203 | | - return this; |
204 | | - } |
205 | | - |
206 | | - /** |
207 | | - * Set the fields to return in results. Makes a defensive copy. |
208 | | - * |
209 | | - * @param returnFields List of field names to return |
210 | | - * @return This builder for chaining |
211 | | - */ |
212 | | - public AggregateHybridQueryBuilder returnFields(List<String> returnFields) { |
213 | | - this.returnFields = returnFields != null ? List.copyOf(returnFields) : List.of(); |
214 | | - return this; |
215 | | - } |
216 | | - |
217 | | - /** |
218 | | - * Set custom stopwords for text search. Makes a defensive copy. |
219 | | - * |
220 | | - * @param stopwords Set of words to exclude from text search |
221 | | - * @return This builder for chaining |
222 | | - */ |
223 | | - public AggregateHybridQueryBuilder stopwords(Set<String> stopwords) { |
224 | | - this.stopwords = stopwords != null ? Set.copyOf(stopwords) : Set.of(); |
225 | | - return this; |
226 | | - } |
227 | | - |
228 | | - /** |
229 | | - * Set the query dialect version. |
230 | | - * |
231 | | - * @param dialect The dialect version (default 2) |
232 | | - * @return This builder for chaining |
233 | | - */ |
234 | | - public AggregateHybridQueryBuilder dialect(int dialect) { |
235 | | - this.dialect = dialect; |
236 | | - return this; |
237 | | - } |
238 | | - |
239 | | - /** |
240 | | - * Build the AggregateHybridQuery instance. |
241 | | - * |
242 | | - * @return The configured AggregateHybridQuery |
243 | | - * @throws IllegalArgumentException if required fields are missing or invalid |
244 | | - */ |
245 | | - public AggregateHybridQuery build() { |
246 | | - return new AggregateHybridQuery(this); |
247 | | - } |
248 | | - |
249 | | - /** |
250 | | - * Convert this builder to a HybridQuery.HybridQueryBuilder for delegation. |
251 | | - * |
252 | | - * @return A HybridQueryBuilder with the same configuration |
253 | | - */ |
254 | | - HybridQuery.HybridQueryBuilder toHybridQueryBuilder() { |
255 | | - return HybridQuery.builder() |
256 | | - .text(text) |
257 | | - .textFieldName(textFieldName) |
258 | | - .vector(vector) |
259 | | - .vectorFieldName(vectorFieldName) |
260 | | - .textScorer(textScorer) |
261 | | - .filterExpression(filterExpression) |
262 | | - .alpha(alpha) |
263 | | - .dtype(dtype) |
264 | | - .numResults(numResults) |
265 | | - .returnFields(returnFields) |
266 | | - .stopwords(stopwords) |
267 | | - .dialect(dialect); |
268 | | - } |
| 75 | + /** |
| 76 | + * Load default stopwords for a given language (delegates to HybridQuery.loadDefaultStopwords()). |
| 77 | + * |
| 78 | + * @param language the language (e.g., "english", "german") |
| 79 | + * @return set of stopwords |
| 80 | + */ |
| 81 | + public static Set<String> loadDefaultStopwords(String language) { |
| 82 | + return HybridQuery.loadDefaultStopwords(language); |
269 | 83 | } |
270 | 84 | } |
0 commit comments