- 后端
- 数据库
【免费下载链接】laravel-mongodb
A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)
导读
本文基于 laravel-mongodb 官方技能文档《Vector Search》展开,系统讲解如何在 Laravel + MongoDB Atlas 场景下基于语义相似度检索文档:通过autoEmbed让 Atlas 自动生成并维护向量、或自行调用嵌入模型手工写入向量,并最终用vectorSearch()一行查询完成语义召回;同时覆盖$rankFusion混合检索(全文 + 向量)与索引生命周期管理。读完本文你将掌握从建索引、写入数据到执行语义查询的完整链路,并理解其底层在 src/Query/Builder.php 与 src/Schema/Blueprint.php 中的真实实现。
一、两种向量检索方案总览
Atlas Vector Search 允许你使用存储在数据旁的 embedding 向量,按语义相似度查询文档。laravel-mongodb 支持两种截然不同的接入方式:
| 方案 | 适用场景 |
|---|---|
| Auto-embedding(自动嵌入) | 文档是纯文本字段;由 Atlas 自动生成并维护向量——无需编写任何 PHP 嵌入代码 |
| Manual embedding(手工嵌入) | 需要自己掌控嵌入模型、需要自定义维度,或要处理非文本数据(如图片、音频) |
两者在索引定义与查询入参上截然不同:自动嵌入用autoEmbed索引类型 + 字符串query;手工嵌入用vector索引类型 + 浮点数组queryVector。下面分别展开。
二、Auto-embedding:文本自动向量化(文本场景推荐)
Atlas 通过autoEmbed索引类型自动生成并维护向量。不需要任何 PHP 代码生成或存储向量——Atlas 在插入(insert)和更新(update)时自动完成嵌入。
2.1 创建 autoEmbed 向量搜索索引
在迁移文件中通过 Laravel Schema 的vectorSearchIndex()创建索引:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::connection('mongodb')->table('products', function ($collection): void { $collection->vectorSearchIndex([ 'fields' => [ [ 'type' => 'autoEmbed', 'modality' => 'text', 'path' => 'description', // source text field 'model' => 'voyage-4', ], ['type' => 'filter', 'path' => 'category'], ], ], 'products_vector'); }); } };关键参数说明:
- 可用模型:
voyage-4、voyage-4-large以及其他 MongoDB 支持提供商提供的模型。 - 可选字段:
numDimensions:向量维度;quantization:量化方式,取值为float|scalar|binary|binaryNoRescore;similarity:相似度度量,取值为euclidean|cosine|dotProduct;indexingMethod:索引算法,取值为flat|hnsw;hnswOptions:HNSW 算法专属选项。
- 索引中的
filter类型字段(如category)用于后续查询的元数据过滤,不参与向量计算。
从源码看,src/Schema/Blueprint.php 中vectorSearchIndex(array $definition, string $name = 'default')的实现是:
$this->collection->createSearchIndex($definition, ['name' => $name, 'type' => 'vectorSearch']);也就是说,该迁移本质上通过createSearchIndexes命令创建了一个type: "vectorSearch"的 Atlas 搜索索引。测试 tests/SchemaTest.php 已验证索引的type为vectorSearch、名称与latestDefinition.fields[0].type均正确。
2.2 正常插入文档——无需嵌入步骤
创建索引后,像平时一样用 Eloquent 写入数据即可,Atlas 会在插入时自动为description字段生成向量:
<?php use App\Models\Product; // Atlas generates the embedding for 'description' automatically on insert Product::create([ 'name' => 'Wireless headphones', 'description' => 'Over-ear noise-cancelling headphones with 30h battery', 'price' => 149.99, ]);2.3 用文本直接查询(Atlas 自动嵌入查询)
<?php use App\Models\Product; $results = Product::vectorSearch( index: 'products_vector', path: 'description', query: 'noise-cancelling headphones for travel', numCandidates: 100, limit: 10, );- 索引使用
autoEmbed时传字符串query;手工提供向量时传浮点数组queryVector,两者互斥。 - 可选的
model参数会覆盖索引上配置的模型(例如用更轻量的模型执行查询嵌入)。 numCandidates控制候选集规模(近似检索时参与排序的候选数量),limit控制最终返回条数。
源码印证:vectorSearch()的完整签名在 src/Query/Builder.php:
public function vectorSearch( string $index, string $path, array|null $queryVector = null, int $limit = 10, bool $exact = false, QueryInterface|array|null $filter = null, int|null $numCandidates = null, string|null $query = null, string|null $model = null, ): Collection两个值得注意的实现细节:
- 版本门槛:
query/model参数要求mongodb/mongodb2.4+。若未满足,src/Query/Builder.php 会抛出BadMethodCallException('The "query" and "model" parameters of vectorSearch() require mongodb/mongodb 2.4+.')。包本身在 composer.json 声明"mongodb/mongodb": "^1.21.2|^2.1.1",因此使用自动嵌入前请确认实际安装版本不低于 2.4。 - 自动打分:查询链路会追加
addFields(vectorSearchScore: ['$meta' => 'vectorSearchScore']),即每条结果都会携带vectorSearchScore字段(见 src/Query/Builder.php),便于排序与展示相关性分数。
测试 tests/AtlasSearchTest.php 中testEloquentBuilderVectorSearchAutoEmbedding展示了完整实践:索引模型用voyage-4-large,查询时用model: 'voyage-4-lite'覆盖(同系列向量相互兼容),并断言结果模型为Book且vectorSearchScore为 float。该测试需要 Atlas 集群配置VOYAGE_API_KEY,否则会跳过。
三、Manual embedding:手工生成向量
当你自行生成向量(如使用 Laravel AI SDK、OpenAI PHP 等)并存入文档时,采用此方案。完整流程始终包含三步:创建索引 → 写入时存储 embedding → 按向量查询。
3.1 创建 vector 类型索引
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up(): void { Schema::connection('mongodb')->table('products', function ($collection): void { $collection->vectorSearchIndex([ 'fields' => [ [ 'type' => 'vector', 'path' => 'embedding', 'numDimensions' => 1536, 'similarity' => 'cosine', ], ['type' => 'filter', 'path' => 'category'], ], ], 'products_vector'); }); } };numDimensions必须与你嵌入模型的输出维度一致(示例中的1536对应 OpenAItext-embedding-3-small);similarity决定向量空间的距离度量(euclidean/cosine/dotProduct),应与查询语义匹配。
3.2 写入时存储 embedding
<?php use App\Models\Product; use OpenAI\Laravel\Facades\OpenAI; $response = OpenAI::embeddings()->create([ 'model' => 'text-embedding-3-small', 'input' => $description, ]); Product::create([ 'name' => 'Wireless headphones', 'description' => $description, 'price' => 149.99, 'embedding' => $response->embeddings[0]->embedding, ]);这里把模型返回的向量数组直接作为文档的embedding字段存储,字段路径必须与索引定义中的path完全一致。
3.3 按向量查询
<?php use App\Models\Product; use OpenAI\Laravel\Facades\OpenAI; $queryVector = OpenAI::embeddings()->create([ 'model' => 'text-embedding-3-small', 'input' => $userQuery, ])->embeddings[0]->embedding; $results = Product::vectorSearch( index: 'products_vector', path: 'embedding', queryVector: $queryVector, numCandidates: 100, limit: 10, );查询参数进阶(均已在vectorSearch()签名中体现,可结合 tests/AtlasSearchTest.php 理解):
exact: true:关闭近似检索(ANN),执行精确暴力扫描。测试testDatabaseBuilderVectorSearch以exact: true传入完全匹配的向量,断言首位结果vectorSearchScore === 1.0。filter:支持QueryInterface|array元数据过滤。测试testEloquentBuilderVectorSearch用Query::query(title: Query::ne('...'))排除精确匹配项,并断言vectorSearchScore处于(0.9, 1.0)区间,证明过滤与评分可以同时生效。- 结果统一由
vectorSearchScore字段携带相关性分数。
Eloquent 层的方法位于 src/Eloquent/Builder.php,它会调用底层 Query Builder 的vectorSearch(),再通过hydrate()将结果水合为模型实例(返回Collection<int, TModel>),因此Product::vectorSearch(...)返回的仍是 Eloquent 模型集合。
四、混合检索:全文 + 向量($rankFusion)
把 Atlas Search 的全文检索($search)与向量检索($vectorSearch)放进同一聚合管道,用$rankFusion做加权融合排序,即可同时兼顾关键词命中与语义相关:
<?php use App\Models\Product; $results = Product::raw(fn ($c) => $c->aggregate([ ['$rankFusion' => [ 'input' => [ 'pipelines' => [ 'fullText' => [ ['$search' => [ 'index' => 'default', 'text' => ['query' => $query, 'path' => 'description'], ]], ], 'semantic' => [ ['$vectorSearch' => [ 'index' => 'products_vector', 'path' => 'embedding', 'queryVector' => $queryVector, 'numCandidates' => 100, 'limit' => 20, ]], ], ], ], 'combination' => ['weights' => ['fullText' => 0.4, 'semantic' => 0.6]], ]], ['$limit' => 10], ]));要点:
input.pipelines中每个命名管道(fullText/semantic)各自产出一个子结果集,$rankFusion会按combination.weights加权合并排序;权重之和不必为 1,但比例决定两路信号的强弱。- 全文管道
$search需要独立的 Atlas Search 索引(示例中名为default,可通过searchIndex()创建);向量管道$vectorSearch使用本文创建的products_vector。 - 外层再叠加
$limit控制最终返回条数。 - 为什么用
raw()而不是vectorSearch()?因为$rankFusion属于较新的聚合阶段。laravel-mongodb 的 src/Query/AggregationBuilder.php 基于mongodb/mongodb的FluentFactoryTrait提供流畅的阶段构建,并提供了addRawStage()兜底——对于库尚未内置的阶段,可直接以原始管道数组的方式拼接,文档示例正是这一用法。
五、索引生命周期管理
除了创建,laravel-mongodb 还提供完整的 Atlas 搜索索引管理能力(均位于 src/Schema/Blueprint.php):
searchIndex(array $definition, string $name = 'default'):创建 Atlas全文Search 索引,底层调用createSearchIndex($definition, ['name' => ..., 'type' => 'search']),适用于$search阶段的全文检索场景。vectorSearchIndex(array $definition, string $name = 'default'):创建向量索引(type: 'vectorSearch'),即本文核心。dropSearchIndex(string $name):删除索引。测试 tests/SchemaTest.php 与 tests/AtlasSearchTest.php 均演示了建索引后dropSearchIndex()清理,避免共享夹具残留。
六、运行前提与注意事项
- 集群规格:需要 AtlasM10+集群,Vector Search 在免费/共享层(Free/Shared tiers)不可用。
- 嵌入提供商密钥:auto-embedding 要求先在 Atlas 中配置好嵌入提供商的 API key(例如
VOYAGE_API_KEY),否则索引创建或查询会失败;测试 tests/AtlasSearchTest.php 通过检测VOYAGE_API_KEY环境变量决定是否跳过。 - 索引构建时间:执行
php artisan migrate后,Atlas 需要几分钟构建索引,请等待索引进入 Ready 状态后再查询(测试中对应waitForSearchIndexesReady()辅助方法)。 - 仅限 Atlas:
$vectorSearch只对 MongoDB Atlas 集群可用,不适用于自托管部署(见 src/Query/Builder.php 的源码注释;src/Schema/Builder.php 也记录了 MongoDB 4~6 / 7-community 不存在createSearchIndexes命令的事实)。 - auto-embedding 的 PHP 端版本要求:
query/model参数需要mongodb/mongodb2.4+(src/Query/Builder.php 会做运行时校验),使用前请确认依赖版本。
附:速查对照
| 能力 | 写法 |
|---|---|
| 建 autoEmbed 索引 | Schema::table(...)内$collection->vectorSearchIndex([...autoEmbed...], 'products_vector') |
| 建 vector 索引 | vectorSearchIndex字段type: 'vector'+numDimensions+similarity |
| 文本语义查询 | Product::vectorSearch(index:, path:, query: '...', numCandidates:, limit:) |
| 向量查询 | Product::vectorSearch(index:, path:, queryVector: $vec, numCandidates:, limit:) |
| 覆盖嵌入模型 | model: 'voyage-4-lite'(作用于 autoEmbed 索引) |
| 精确检索 / 过滤 | exact: true、filter: Query::query(...) |
| 混合排序 | Product::raw(fn ($c) => $c->aggregate([...'$rankFusion'...])) |
| 删索引 | Schema::table(...)内$collection->dropSearchIndex('products_vector') |
以上全部操作均以当前仓库 src 下源码与 tests/AtlasSearchTest.php、tests/SchemaTest.php 的真实实现与测试用例为佐证,可直接在项目中对照验证。
- 后端
- 数据库
【免费下载链接】laravel-mongodb
A MongoDB based Eloquent model and Query builder for Laravel (Moloquent)
相关推荐
Mongoose Atlas Vector Search 实战:从向量索引创建到 $vectorSearch 语义检索
Mongoose Atlas Vector Search 实战:从向量索引创建到 $vectorSearch 语义检索 Atlas Vector Search
数据库后端Azure AI Search .NET SDK 实战指南:类型安全索引、向量/混合检索与语义排序
Azure AI Search .NET SDK 实战指南:类型安全索引、向量/混合检索与语义排序 本篇技术指南围绕 autoskills 仓库中 azure
Photo Abstract Editorial 完整上手指南:新手也能把普通照片变成抽象编辑作品
Photo Abstract Editorial 完整上手指南:新手也能把普通照片变成抽象编辑作品 把普通照片变成有艺术感的抽象编辑作品,听起来需要专业设计功底
AI 技能媒体生成AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考