001/* 002 * Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.agentsflex.core.store; 017 018import com.agentsflex.core.store.condition.*; 019 020import java.util.*; 021import java.util.function.Consumer; 022 023public class SearchWrapper extends VectorData { 024 025 /** 026 * the default value of search data count 027 */ 028 public static final int DEFAULT_MAX_RESULTS = 4; 029 030 /** 031 * search text, Vector store will convert the text to vector data 032 */ 033 private String text; 034 035 /** 036 * search max result, like the sql "limit" in mysql 037 */ 038 private Integer maxResults = DEFAULT_MAX_RESULTS; 039 040 /** 041 * The lowest correlation score, ranging from 0 to 1 (including 0 and 1). Only embeddings with a score of this value or higher will be returned. 042 * 0.0 indicates accepting any similarity or disabling similarity threshold filtering. A threshold of 1.0 indicates the need for a perfect match. 043 */ 044 private Double minScore; 045 046 /** 047 * The flag of include vector data queries. If the current value is true and the vector content is null, 048 * the query text will be automatically converted into vector data through the vector store. 049 */ 050 private boolean withVector = true; 051 052 /** 053 * query condition 054 */ 055 private Condition condition; 056 057 /** 058 * query fields 059 */ 060 private List<String> outputFields; 061 062 /** 063 * whether to output vector data 064 */ 065 private boolean outputVector = false; 066 067 068 private List<String> partitionNames; 069 070 071 public String getText() { 072 return text; 073 } 074 075 public void setText(String text) { 076 this.text = text; 077 } 078 079 public SearchWrapper text(String text) { 080 setText(text); 081 return this; 082 } 083 084 public Integer getMaxResults() { 085 return maxResults; 086 } 087 088 public void setMaxResults(Integer maxResults) { 089 this.maxResults = maxResults; 090 } 091 092 public SearchWrapper maxResults(Integer maxResults) { 093 setMaxResults(maxResults); 094 return this; 095 } 096 097 public Double getMinScore() { 098 return minScore; 099 } 100 101 public void setMinScore(Double minScore) { 102 this.minScore = minScore; 103 } 104 105 public SearchWrapper minScore(Double minScore) { 106 setMinScore(minScore); 107 return this; 108 } 109 110 public boolean isWithVector() { 111 return withVector; 112 } 113 114 public void setWithVector(boolean withVector) { 115 this.withVector = withVector; 116 } 117 118 public SearchWrapper withVector(Boolean withVector) { 119 setWithVector(withVector); 120 return this; 121 } 122 123 public Condition getCondition() { 124 return condition; 125 } 126 127 public void setCondition(Condition condition) { 128 this.condition = condition; 129 } 130 131 public List<String> getOutputFields() { 132 return outputFields; 133 } 134 135 public void setOutputFields(List<String> outputFields) { 136 this.outputFields = outputFields; 137 } 138 139 public SearchWrapper outputFields(Collection<String> outputFields) { 140 setOutputFields(new ArrayList<>(outputFields)); 141 return this; 142 } 143 144 public SearchWrapper outputFields(String... outputFields) { 145 setOutputFields(Arrays.asList(outputFields)); 146 return this; 147 } 148 149 public boolean isOutputVector() { 150 return outputVector; 151 } 152 153 public void setOutputVector(boolean outputVector) { 154 this.outputVector = outputVector; 155 } 156 157 public SearchWrapper outputVector(boolean outputVector) { 158 setOutputVector(outputVector); 159 return this; 160 } 161 162 163 public SearchWrapper eq(String key, Object value) { 164 return eq(Connector.AND, key, value); 165 } 166 167 public SearchWrapper eq(Connector connector, String key, Object value) { 168 if (this.condition == null) { 169 this.condition = new Condition(ConditionType.EQ, new Key(key), new Value(value)); 170 } else { 171 this.condition.connect(new Condition(ConditionType.EQ, new Key(key), new Value(value)), connector); 172 } 173 return this; 174 } 175 176 public SearchWrapper ne(String key, Object value) { 177 return ne(Connector.AND, key, value); 178 } 179 180 public SearchWrapper ne(Connector connector, String key, Object value) { 181 if (this.condition == null) { 182 this.condition = new Condition(ConditionType.NE, new Key(key), new Value(value)); 183 } else { 184 this.condition.connect(new Condition(ConditionType.NE, new Key(key), new Value(value)), connector); 185 } 186 return this; 187 } 188 189 public SearchWrapper gt(String key, Object value) { 190 return gt(Connector.AND, key, value); 191 } 192 193 public SearchWrapper gt(Connector connector, String key, Object value) { 194 if (this.condition == null) { 195 this.condition = new Condition(ConditionType.GT, new Key(key), new Value(value)); 196 } else { 197 this.condition.connect(new Condition(ConditionType.GT, new Key(key), new Value(value)), connector); 198 } 199 return this; 200 } 201 202 203 public SearchWrapper ge(String key, Object value) { 204 return ge(Connector.AND, key, value); 205 } 206 207 public SearchWrapper ge(Connector connector, String key, Object value) { 208 if (this.condition == null) { 209 this.condition = new Condition(ConditionType.GE, new Key(key), new Value(value)); 210 } else { 211 this.condition.connect(new Condition(ConditionType.GE, new Key(key), new Value(value)), connector); 212 } 213 return this; 214 } 215 216 217 public SearchWrapper lt(String key, Object value) { 218 return lt(Connector.AND, key, value); 219 } 220 221 public SearchWrapper lt(Connector connector, String key, Object value) { 222 if (this.condition == null) { 223 this.condition = new Condition(ConditionType.LT, new Key(key), new Value(value)); 224 } else { 225 this.condition.connect(new Condition(ConditionType.LT, new Key(key), new Value(value)), connector); 226 } 227 return this; 228 } 229 230 231 public SearchWrapper le(String key, Object value) { 232 return le(Connector.AND, key, value); 233 } 234 235 public SearchWrapper le(Connector connector, String key, Object value) { 236 if (this.condition == null) { 237 this.condition = new Condition(ConditionType.LE, new Key(key), new Value(value)); 238 } else { 239 this.condition.connect(new Condition(ConditionType.LE, new Key(key), new Value(value)), connector); 240 } 241 return this; 242 } 243 244 245 public SearchWrapper in(String key, Collection<?> values) { 246 return in(Connector.AND, key, values); 247 } 248 249 public SearchWrapper in(Connector connector, String key, Collection<?> values) { 250 if (this.condition == null) { 251 this.condition = new Condition(ConditionType.IN, new Key(key), new Value(values.toArray())); 252 } else { 253 this.condition.connect(new Condition(ConditionType.IN, new Key(key), new Value(values.toArray())), connector); 254 } 255 return this; 256 } 257 258 public SearchWrapper min(String key, Object value) { 259 return min(Connector.AND, key, value); 260 } 261 262 public SearchWrapper min(Connector connector, String key, Object value) { 263 if (this.condition == null) { 264 this.condition = new Condition(ConditionType.NIN, new Key(key), new Value(value)); 265 } else { 266 this.condition.connect(new Condition(ConditionType.NIN, new Key(key), new Value(value)), connector); 267 } 268 return this; 269 } 270 271 public SearchWrapper between(String key, Object start, Object end) { 272 return between(Connector.AND, key, start, end); 273 } 274 275 public SearchWrapper between(Connector connector, String key, Object start, Object end) { 276 if (this.condition == null) { 277 this.condition = new Condition(ConditionType.BETWEEN, new Key(key), new Value(start, end)); 278 } else { 279 this.condition.connect(new Condition(ConditionType.BETWEEN, new Key(key), new Value(start, end)), connector); 280 } 281 return this; 282 } 283 284 285 public SearchWrapper group(SearchWrapper wrapper) { 286 return group(wrapper.condition); 287 } 288 289 public SearchWrapper group(Condition condition) { 290 if (this.condition == null) { 291 this.condition = new Group(condition); 292 } else { 293 this.condition.connect(new Group(condition), Connector.AND); 294 } 295 return this; 296 } 297 298 public SearchWrapper group(Consumer<SearchWrapper> consumer) { 299 SearchWrapper newWrapper = new SearchWrapper(); 300 consumer.accept(newWrapper); 301 Condition condition = newWrapper.condition; 302 if (condition != null) { 303 group(condition); 304 } 305 return this; 306 } 307 308 public SearchWrapper andCriteria(Consumer<SearchWrapper> consumer) { 309 return group(consumer); 310 } 311 312 public SearchWrapper orCriteria(Consumer<SearchWrapper> consumer) { 313 SearchWrapper newWrapper = new SearchWrapper(); 314 consumer.accept(newWrapper); 315 Condition condition = newWrapper.condition; 316 if (condition != null) { 317 if (this.condition == null) { 318 this.condition = new Group(condition); 319 } else { 320 this.condition.connect(new Group(condition), Connector.OR); 321 } 322 } 323 return this; 324 } 325 326 /** 327 * Convert to expressions for filtering conditions, with different expression requirements for each vendor. 328 * Customized adaptor can be achieved through ExpressionAdaptor 329 */ 330 public String toFilterExpression() { 331 return toFilterExpression(ExpressionAdaptor.DEFAULT); 332 } 333 334 public String toFilterExpression(ExpressionAdaptor adaptor) { 335 if (this.condition == null) { 336 return null; 337 } else { 338 Objects.requireNonNull(adaptor, "adaptor must not be null"); 339 return this.condition.toExpression(adaptor); 340 } 341 } 342 343 public List<String> getPartitionNames() { 344 return partitionNames; 345 } 346 347 public void setPartitionNames(List<String> partitionNames) { 348 this.partitionNames = partitionNames; 349 } 350}