咱们PHPer做项目时,要是想搞个向量搜索、全文检索,或者混合搜索,之前总免不了要用Python的库,或者依赖外部的向量数据库,不仅技术栈割裂,部署起来也麻烦。
最近发现PHPVector这个纯PHP实现的向量数据库,把HNSW近似最近邻搜索、BM25全文检索都给实现了,还能把两者组合成混合搜索管道,关键是不用啥复杂的外部扩展,PHP8.2+就能跑,简直是为咱们量身定做的。
PHPVector核心能力
简单说,PHPVector 能帮你搞定这几件事:
- 向量搜索:用 HNSW 算法快速找和查询向量最相似的文档,适合做语义搜索、推荐系统这类场景;
- 全文搜索:用经典的 BM25 算法根据文本关键词做相关性排序,和传统的全文检索体验一样;
- 混合搜索:把向量相似度和 BM25 分数融合起来,既能抓语义,又能匹配关键词,搜索结果更准;
- 轻量持久化:基于文件夹存数据,内存占用低,插入还能异步(装个 ext-pcntl 就行),生产环境用着也放心。
快速上手,5分钟跑通核心流程
话不多说,直接上代码,跟着做一遍就能明白怎么用。
第一步:安装
用 Composer 一键安装:
composer require ezimuel/phpvector
第二步:插入文档
文档里可以放向量、原始文本,还有任意你想随结果返回的元数据,id要是不填,会自动生成UUID v4:
usePHPVector\Document;usePHPVector\VectorDatabase;// 先初始化数据库$db = new VectorDatabase();// 批量插入文档$db->addDocuments([new Document( id: 1, vector: [0.12, 0.85, 0.44, 0.67], // 密集嵌入向量 text: 'PHP vector database with HNSW index', // 用于 BM25 的文本 metadata: ['url' => 'https://example.com/1', 'lang' => 'en'], // 自定义元数据 ),new Document( id: 2, vector: [0.91, 0.23, 0.78, 0.05], text: 'Approximate nearest neighbour search in PHP', metadata: ['url' => 'https://example.com/2', 'lang' => 'en'], ),new Document( vector: [0.55, 0.42, 0.71, 0.30], // 不填 id 自动生成 UUID text: 'Hybrid search with Reciprocal Rank Fusion', ),]);
第三步:向量搜索
用HNSW找最相似的k个文档,直接返回排名、分数和文档信息:
// 假设这是你的查询向量$queryVector = [0.10, 0.80, 0.50, 0.60];// 找 top 2 相似文档$results = $db->vectorSearch(vector: $queryVector, k: 2);// 遍历输出结果foreach ($results as $result) {echo sprintf("[%d] score=%.4f %s\n", $result->rank, $result->score, $result->document->metadata['url'] ?? '无链接', );}// 输出大概长这样:// [1] score=0.9987 https://example.com/1// [2] score=0.8341 https://example.com/3
第四步:全文搜索
用BM25根据文本关键词做相关性排序,和普通全文搜索体验一样:
// 文本查询$results = $db->textSearch(query: 'nearest neighbour PHP', k: 2);foreach ($results as $result) {echo sprintf("[%d] score=%.4f %s\n", $result->rank, $result->score, $result->document->metadata['url'] ?? '无链接', );}// 输出:// [1] score=1.2430 https://example.com/2// [2] score=0.8761 https://example.com/1
第五步:混合搜索(推荐)
把向量和文本搜索的结果融合起来,有两种方式:
usePHPVector\HybridMode;// 方式1:RRF 融合(推荐)$results = $db->hybridSearch( vector: $queryVector, text: 'vector database PHP', k: 3, mode: HybridMode::RRF,);// 方式2:加权组合(比如向量权重 0.7,文本权重 0.3)$results = $db->hybridSearch( vector: $queryVector, text: 'vector database PHP', k: 3, mode: HybridMode::Weighted, vectorWeight: 0.7, textWeight: 0.3,);// 输出结果和前面一样,直接遍历就行
想更精准可以调这些配置
HNSW和 BM25都支持自定义配置,根据你的场景调一调,效果会更好:
usePHPVector\BM25\ConfigasBM25Config;usePHPVector\BM25\SimpleTokenizer;usePHPVector\Distance;usePHPVector\HNSW\ConfigasHNSWConfig;usePHPVector\VectorDatabase;$db = new VectorDatabase(// HNSW 配置 hnswConfig: new HNSWConfig( M: 16, // 每层节点最大连接数,越高召回越好但内存占得多 efConstruction: 200, // 建索引时的束宽,越高图质量越好但插入慢 efSearch: 50, // 查询时的束宽,越高召回越好但查询慢 distance: Distance::Cosine, // 距离度量:文本嵌入用 Cosine,原始向量用 Euclidean useHeuristic: true, // 推荐启用,邻居选择更多样化 ),// BM25 配置 bm25Config: new BM25Config( k1: 1.5, // TF 饱和度,推荐 1.2-2.0 b: 0.75, // 长度归一化,0=不归一,1=完全归一 ),// 分词器配置 tokenizer: new SimpleTokenizer( stopWords: SimpleTokenizer::DEFAULT_STOP_WORDS, // 停用词 minTokenLength: 2, // 最小分词长度 ),);
这里顺便提下距离度量怎么选:
Distance::Cosine:文本嵌入、已归一化向量(最常用)Distance::Euclidean:原始未归一化向量Distance::DotProduct:单位归一化向量(比 Cosine 更快)Distance::Manhattan:稀疏向量,对异常值更鲁棒
生产环境必看:持久化怎么搞
PHPVector用文件夹存数据,每个数据库对应一个目录,里面存HNSW图、BM25索引和单个文档文件,优势是加载时内存占用低(只加载索引,文档懒加载),插入还能异步(装 ext-pcntl 就行)。
保存数据
usePHPVector\Document;usePHPVector\VectorDatabase;// 初始化时指定存储路径$db = new VectorDatabase(path: '/var/data/mydb');// 插入文档(装了 ext-pcntl 会异步写入文档文件)$db->addDocuments([new Document(id: 1, vector: [0.12, 0.85, 0.44], text: 'PHP vector search'),new Document(id: 2, vector: [0.91, 0.23, 0.78], text: 'Approximate nearest neighbour'),]);// 最后调用 save() 把 HNSW 图和 BM25 索引刷盘(会等异步写入完成)$db->save();
加载数据
// 直接 open 已保存的数据库就行$db = VectorDatabase::open('/var/data/mydb');// 接下来直接搜索,和之前一样用$results = $db->vectorSearch(vector: $queryVector, k: 2);
最后
PHPVector最香的地方就是让咱们不用跳出自己的技术栈,就能在项目里加向量搜索、混合搜索这类能力,不管是做个智能搜索、推荐系统,还是知识库问答,都能轻松搞定。
而且它足够轻量不需要外部依赖,部署起来也简单,小项目用它完全够用,大项目也能先拿它做一个原型验证,感兴趣的朋友不妨可以试试!