如何在Redis OM Spring中实现同时对name和code字段的自动补全搜索
如何在Redis OM Spring中实现同时对name和code字段的自动补全搜索
我明白你现在的需求是想在Redis OM Spring里用一个查询同时覆盖name和code两个字段的自动补全,而不是分开调用两个方法。先帮你分析下问题根源,再给你两种可行的解决方案:
为什么你之前的generic search方法会报错?
Redis OM Spring的自动补全方法是严格遵循命名约定的:必须以autoComplete开头,后面紧跟字段名(比如autoCompleteName对应name字段,autoCompleteCode对应code字段)。你自定义的search方法不符合这个命名规则,框架无法识别要关联哪个自动补全索引,所以抛出了数组越界的异常。
解决方案1:合并两个自动补全查询的结果
这种方法不需要修改实体类或仓库接口,只需要在Controller层同时调用两个自动补全方法,再合并结果并去重即可:
修改你的Controller代码:
@RestController @RequestMapping("/stations") class AirportsController( private val repository: StationsRepository, private val objectMapper: ObjectMapper // 记得注入Jackson的ObjectMapper ) { @GetMapping("/search") fun query(@RequestParam("q") query: String?): MutableList<Suggestion?>? { val options = AutoCompleteOptions.get().withPayload() // 同时查询name和code字段的自动补全结果 val nameSuggestions = repository.autoCompleteName(query, options) ?: mutableListOf() val codeSuggestions = repository.autoCompleteCode(query, options) ?: mutableListOf() // 合并结果并去重(这里用station的code作为唯一标识去重) val combinedSuggestions = mutableListOf<Suggestion?>() val seenStationCodes = mutableSetOf<String>() (nameSuggestions + codeSuggestions).forEach { suggestion -> suggestion?.let { // 从payload中解析出完整的Station对象 val payloadJson = it.payload ?: return@let val station = objectMapper.readValue(payloadJson, AutoSearchStation::class.java) // 只添加未出现过的station if (seenStationCodes.add(station.code)) { combinedSuggestions.add(it) } } } return combinedSuggestions } }
这种方案的优点是快速实现,不需要改动现有实体和仓库结构;缺点是需要执行两次自动补全查询,数据量大时可能有轻微性能损耗,且去重逻辑需要自己维护。
解决方案2:创建联合自动补全字段
如果追求更优的查询性能,可以在实体类中新增一个联合字段,把name和code的内容合并进去,然后对这个字段做自动补全:
1. 修改实体类
新增一个searchText字段,用于合并name和code的内容,并标记为自动补全字段:
@Document data class AutoSearchStation( @Id @AutoComplete @AutoCompletePayload(fields = ["name", "code", "lat", "lng"]) var code: String = "", @AutoComplete @AutoCompletePayload(fields = ["name", "code", "lat", "lng"]) var name: String = "", @AutoComplete @AutoCompletePayload(fields = ["name", "code", "lat", "lng"]) var searchText: String = "", // 联合搜索字段 @AutoCompletePayload(fields = ["name", "code", "lat", "lng"]) var lat: Double = 0.0, @AutoCompletePayload(fields = ["name", "code", "lat", "lng"]) var lng: Double = 0.0 ) { // 保存前自动更新联合字段(可以在Service层调用,或者用@PrePersist注解) fun updateSearchText() { this.searchText = "$name $code" } }
2. 扩展仓库接口
新增针对searchText字段的自动补全方法:
interface StationsRepository : RedisDocumentRepository<AutoSearchStation?, String?> { // 保留原有的4个方法 fun autoCompleteName(query: String?): MutableList<Suggestion?>? fun autoCompleteName(query: String?, options: AutoCompleteOptions?): MutableList<Suggestion?>? fun autoCompleteCode(query: String?): MutableList<Suggestion?>? fun autoCompleteCode(query: String?, options: AutoCompleteOptions?): MutableList<Suggestion?>? // 新增联合字段的自动补全方法 fun autoCompleteSearchText(query: String?): MutableList<Suggestion?>? fun autoCompleteSearchText(query: String?, options: AutoCompleteOptions?): MutableList<Suggestion?>? }
3. 保存实体时更新联合字段
在Service层(或保存实体的地方),记得调用updateSearchText()方法:
// 举个例子,Service层保存逻辑 fun saveStation(station: AutoSearchStation) { station.updateSearchText() repository.save(station) }
4. 修改Controller查询逻辑
现在只需要调用联合字段的自动补全方法即可:
@GetMapping("/search") fun query(@RequestParam("q") query: String?): MutableList<Suggestion?>? { return repository.autoCompleteSearchText(query, AutoCompleteOptions.get().withPayload()) }
这种方案的优点是查询效率更高(只需要一次自动补全查询),逻辑更简洁;缺点是需要额外维护一个联合字段,必须确保实体保存时这个字段被正确更新。
内容来源于stack exchange
相关产品推荐
相关产品推荐

