Laravel+Predis调用Redis搜相似向量报错:toArray()方法调用异常
问题
我希望在Laravel中通过Redis结合OpenAI Embeddings实现相似向量检索,现有可正常运行的Python示例代码如下:
def search_similar_documents(self, entity_id, vector, topK=5): query = Query("*=>[KNN 2 @embedding $vec as score]") query.sort_by("score") query.return_fields("score") query.paging(0, 2) query.dialect(2) query_params = {"vec": vector} return self.r.ft(self.index_name).search(query, query_params)
但编写的Laravel对应代码执行时出现错误:Call to a member function toArray() on array,错误位置在vendor\predis\predis\src\Command\Redis\Search\FTSEARCH.php第34行。添加日志查看参数传递情况后仍无法明确问题,Laravel代码及日志信息如下:
Laravel代码:
public function searchSimilarityDocuments(int $entityId, array $vector, int $topK=2){ $filter = '*=>[KNN '.$topK.' @embedding $vec as score]'; // $filter = ["vec" => json_encode($vector)]; $arguments = new SearchArguments(); $arguments->withScores(); $arguments->withPayloads(); $arguments->filter($filter); $vector = pack('f*', ...$vector); $result = $this->r->ftSearch($this->indexName, $arguments, ['vec' => $vector]); return $result; }
添加的日志代码:
public function setArguments(array $arguments) { [$index, $query] = $arguments; Log::info($arguments); $commandArguments = (!empty($arguments[2])) ? $arguments[2]->toArray() : []; parent::setArguments(array_merge( [$index, $query], $commandArguments )); }
日志片段:
[2023-08-25 04:58:14] local.INFO: array ( 0 => 'conversations', 1 => Predis\Command\Argument\Search\SearchArguments::__set_state(array( 'sortingEnum' => array ( 'asc' => 'ASC', 'desc' => 'DESC', ), 'arguments' => array ( 0 => 'WITHSCORES', 1 => 'WITHPAYLOADS', 2 => 'FILTER', 3 => '*=>[KNN 2 @embedding $vec as score]', ), )), 2 => array ( 'vec' => '$���E�;ǻ���h���켩ǫ<�vX;��`����寍... ), )
请问如何解决该错误,实现Laravel中Redis相似向量检索功能?
解决方法
1. 修复参数传递逻辑
错误根源是ftSearch方法的第三个参数被当成SearchArguments对象调用toArray(),但实际传入的是普通绑定参数数组。Predis的ftSearch要求参数绑定需作为命令参数的一部分,而非单独的第三个参数。
方法一:使用SearchArguments规范传参(推荐)
public function searchSimilarityDocuments(int $entityId, array $vector, int $topK=2){ $knnQuery = "*=>[KNN {$topK} @embedding $vec as score]"; $arguments = new SearchArguments(); // 基础查询配置 $arguments->query($knnQuery); $arguments->withScores(); $arguments->withPayloads(); // 匹配Python示例的分页、排序、方言版本 $arguments->limit(0, 2); $arguments->sortBy('score', 'DESC'); $arguments->dialect(2); // 绑定向量参数(转为二进制格式) $arguments->parameters(['vec' => pack('f*', ...$vector)]); return $this->r->ftSearch($this->indexName, $arguments); }
方法二:直接构造原生Redis命令数组
如果SearchArguments的参数绑定不生效,可直接构造符合Redis Search语法的命令数组:
public function searchSimilarityDocuments(int $entityId, array $vector, int $topK=2){ $knnQuery = "*=>[KNN {$topK} @embedding $vec as score]"; $packedVector = pack('f*', ...$vector); $commandArgs = [ $this->indexName, $knnQuery, 'WITHSCORES', 'WITHPAYLOADS', 'DIALECT', '2', 'LIMIT', 0, 2, 'SORTBY', 'score', 'DESC', 'PARAMS', 2, 'vec', $packedVector ]; return $this->r->executeRaw($commandArgs); }
2. 修复日志代码的类型判断问题
自定义的setArguments错误地假设第三个参数是对象,修改为兼容数组和对象的逻辑:
public function setArguments(array $arguments) { [$index, $query] = $arguments; Log::info($arguments); $commandArguments = []; if (!empty($arguments[2])) { $commandArguments = is_object($arguments[2]) ? $arguments[2]->toArray() : $arguments[2]; } parent::setArguments(array_merge( [$index, $query], $commandArguments )); }
3. 关键注意事项
- 必须指定
DIALECT 2:Redis Search的KNN参数绑定语法仅在dialect 2及以上版本支持,需和Python示例保持一致。 - 向量格式匹配:使用
pack('f*', ...$vector)将浮点数组转为二进制格式,确保和Redis中存储的向量编码一致。 - 参数绑定格式:通过
PARAMS关键字传递参数,格式为PARAMS [键值对数量] [键1] [值1] [键2] [值2]。
内容的提问来源于stack exchange,提问作者Danilo Toro
相关产品推荐
相关产品推荐

