ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Medusa PostgreSQL 搜索引擎:native 与 lakebase 双引擎配置、向量混合检索与过滤分面全解析

Medusa PostgreSQL 搜索引擎:native 与 lakebase 双引擎配置、向量混合检索与过滤分面全解析 Medusa PostgreSQL 搜索引擎native 与 lakebase 双引擎配置、向量混合检索与过滤分面全解析【免费下载链接】medusaThe worlds most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa本文围绕 Medusa 开源仓库中medusajs/search-postgres模块展开它是 Medusa 默认的 Search Module Provider由 PostgreSQL 原生能力与 Lakebase Search 双引擎驱动。文章完整讲解如何在medusa-config.ts中启用该 Provider如何用defineSearchIndex定义索引与向量字段以及关键词检索、向量/混合检索ANN RRF、过滤语义、分面统计与min_score/distinct等能力的使用方法并给出底层 SQL 与源码实现证据帮助你在本地自托管和 Medusa Cloud 两种环境下正确落地搜索功能。一、Provider 概览一个 Provider、两套引擎在 Medusa 的模块体系中medusajs/search-postgres是一个通过ModuleProvider(Modules.SEARCH, ...)注册的搜索 Provider见 src/index.ts其服务类PostgresSearchService继承自框架的AbstractSearchProviderService见 src/services/postgres-search.ts。它没有依赖第三方搜索引擎而是直接用 PostgreSQL 自身的数据结构来完成全文检索与向量检索因此部署成本极低。Provider 内置两套引擎通过options.engine切换Engine适用场景关键词检索向量检索native默认本地开发 / 自托管 / 任意 PostgreSQLGIN ts_rankpg_trgm不支持lakebaseMedusa Cloud / Lakebase Searchlakebase_bm25BM25 排序lakebase_annANN从源码看引擎选项在服务构造时被校验非native/lakebase的值会抛出INVALID_DATA错误见 postgres-search.ts。也就是说本地与自托管请使用默认的native只有部署在 Medusa Cloud或具备 Lakebase Search 扩展的 PG16 环境才适合切到lakebase这一点在 utils/extensions.ts 的注释中也有明确说明。二、启用 Provider两种引擎的配置方式1. native 引擎默认本地与 Medusa Cloud 均可在项目的medusa-config.ts中将 Provider 注册到 Search 模块的providers数组modules: [ { resolve: medusajs/medusa/search, options: { providers: [ { resolve: medusajs/medusa/search-postgres, id: postgres, options: { // engine: native, // 默认值 // language: english, }, }, ], }, }, ]2. lakebase 引擎仅 Medusa Cloud{ resolve: medusajs/medusa/search-postgres, id: postgres, options: { engine: lakebase, // 可选为 search_options.vector.query 提供文本向量化能力 // embedder: async (text) { ... return number[] }, // vector_distance: cosine, // 或 l2 | inner_product }, }需要注意embedder必须是(text: string) Promisenumber[]形式的异步函数类型定义见 utils/plan.ts它承担两个职责写入时为声明了.embed()的向量字段把源文本编码成向量查询时把search_options.vector.query的文本编码成查询向量。3. 执行数据库迁移配置完成后在项目根目录依次执行两条命令npx medusa db:migrate npx medusa db:migrate-search迁移脚本 Migration20260807120000.ts 会完成三件事启用pg_trgm与unaccent扩展使用DO $$ ... EXCEPTION WHEN OTHERS包裹权限不足时软失败仅打 NOTICE不影响迁移继续创建medusa_search_english文本搜索配置——它复制自english配置并把word、hword、hword_part的映射改为unaccent, english_stem从而实现忽略重音的全文本检索创建索引目录表search_postgres_index字段为name、table_name、schema_hash、plan、document_count、created_at、updated_at主键name。在 Medusa Cloud 上迁移还会通过CREATE EXTENSION ... CASCADE启用lakebase_vector与lakebase_text这些语句在不提供 Lakebase Search 的引擎上会软失败因此本地不会因为缺少扩展而迁移失败。三、Provider 选项一览选项默认值说明enginenative可选native或lakebaselanguageenglish文本搜索配置语言。配合unaccent会生成medusa_search_language搜索配置embedder无(text) Promisenumber[]lakebase 下使用search_options.vector.query时的必填项vector_distancecosineANN 距离度量cosine、l2或inner_product两个值得展开的细节language校验服务构造时会用正则/^[a-z0-9_]$/i校验语言名非法值直接抛错见 postgres-search.ts。这意味着你可以配置simple、german等 PostgreSQL 内置配置名但对应需要存在medusa_search_language配置。如果自定义语言需在数据库中先创建同名搜索配置utils/extensions.ts 对此有说明。vector_distance与索引的对应关系cosine对应vector_cosine_ops运算符l2对应vector_l2_ops运算符-inner_product对应vector_ip_ops运算符#。在 lakebase 引擎下创建文档表时每个向量列都会按所选度量建立lakebase_ann索引见 postgres-search.ts 与 utils/plan.ts。四、向量字段仅 lakebase 引擎1. 客户端自供向量在索引定义中声明一个vector类型的字段写入文档时必须带上与dimensions一致的数值数组defineSearchIndex({ name: product, entity: product, fields: search.define({ id: search.keyword().filterable(), title: search.text().searchable({ weight: 3 }), embedding: search.vector(1536), }), // ... })源码中coerceVector会对写入的向量做严格校验必须是纯数值数组、不能含 NaN、长度必须等于声明的维度数否则拒绝写入见 utils/documents.ts。2. 让 Provider 自动向量化文本.embed()如果不想自己维护向量可以在字段上调用.embed()让 Provider 用配置的embedder把一段文本编码成向量embedding: search.vector(1536).embed() // 文档写入{ embedding: title and description to encode } await query.search({ entity: product, search_options: { vector: { field: embedding, query: red shoes, semantic_ratio: 0.5, // 0 纯关键词1 纯向量中间值 RRF 混合 }, }, })这里有两个关键约束均来自源码.embed()字段的文档值必须是字符串非字符串会被拒绝sourceTextForEmbed的检查见 utils/documents.ts配置了.embed()就必须提供embedder否则在索引 upsert 时直接抛INVALID_ARGUMENT错误assertEmbedderForPlan见 postgres-search.ts。写入流程上applyEngineEmbeddings会并行调用embedder并校验返回向量的维度是否与字段声明一致见 postgres-search.ts。3. 用客户端向量查询若向量由客户端提供直接用value传入 embedding 数组即可两种字段都适用await query.search({ entity: product, filters: { q: red shoes }, search_options: { vector: { field: embedding, value: embeddingArray, semantic_ratio: 0.5, }, }, })查询侧同样有维度校验value的长度必须等于字段维度见 postgres-search.ts。vector.field在索引只有一个向量字段时可以省略若有多个向量字段则必须显式指定见 utils/plan.ts。另外semantic_ratio有一个默认推导逻辑见 postgres-search.ts既有q又有vector选项默认0.5混合只有vector无q默认1纯向量有q无vector走纯关键词路径。五、能力矩阵native 与 lakebase 的功能对比能力nativelakebase自由文本ts_rank 权重lakebase_bm25BM25拼写容错pg_trgmword_similaritypg_trgm相同match_strategyall默认、any、last相同过滤$eq$ne$in$nin范围、$and/$or/$not等相同分面value、range、stats——限定在查询命中集内统计相同distinct每个值一条命中计数随之生效相同min_score支持保留请求的排序相同向量 / 混合检索—ANN RRF两种引擎都会显式拒绝以下能力高亮highlighting、地理检索geo、游标分页cursor pagination、查询时指定 localequery-time locales。拒绝逻辑集中在assertQuerySupported见 utils/plan.ts。其中 locale 需要通过 Provider 的language选项配置而不是查询参数geo 字段在索引定义阶段assertIndexSupported就会被拒绝原生引擎下声明vector字段同样会在索引阶段报错。match_strategy: last是 typeahead前缀联想语义前面的词必须完整匹配最后一个词按前缀匹配。例如dtc sta可以命中Dtc starter。源码中它通过给最后一个词素追加:*构造 tsquery 实现见 utils/plan.ts。六、过滤语义Filter Semantics过滤器的编译逻辑在 utils/filters.ts 中核心要点如下1. 等值与$in走 jsonb 包含等值过滤和$in会被编译为indexed …的 jsonb 包含表达式这种谓词恰好能被jsonb_path_opsGIN 索引加速并且对数字和布尔值做原生类型比较不像?|只匹配字符串数组元素。例如status: published实际生成类似indexed {status:published}::jsonb的语句见 filters.ts。2. 数组字段的成员语义对数组字段传裸值或$eq表示成员关系{ tags: sale }会命中tags数组包含sale的文档。等值$eq在数组字段上同样编译为包含表达式只是叶子值包了一层数组见 filters.ts。3. 数组字段上被禁止的操作范围操作符$gt、$gte、$lt、$lte、$prefix、$like在数组字段上会被显式拒绝并抛错见 filters.ts。4. 布尔逻辑与本地localProvider 不同$and、$or、$not在 Postgres 上都能被原样表达因此全部支持见 filters.ts。此外还支持$exists、$contains数组包含全部、$overlaps数组存在交集、$ne、$nin。注意$ne的语义是缺失该字段的文档也满足不等于见 filters.ts。5. 过滤字段必须是已声明的字段查询中引用索引未声明的过滤字段会直接报 Unknown filter field防止拼写错误静默失效。七、混合检索Hybrid Queries仅 lakebase当同时提供关键词q和向量选项且0 semantic_ratio 1时Provider 走混合检索路径searchHybrid见 postgres-search.ts需要注意以下行为结果只能按_score排序混合结果经 RRFReciprocal Rank Fusion融合后再按字段排序没有意义因此代码会显式拒绝_score之外的排序键见 postgres-search.tsRRF 融合公式关键词臂权重为1 - semantic_ratio向量臂权重为semantic_ratio每个臂的得分贡献为weight / (k rank 1)其中k 60。因此单臂贡献最大约为weight / 61混合检索下min_score是在这个 RRF 尺度上比较的见 postgres-search.tsmetadata.count是两臂命中集合的并集精确大小因为融合后的命中列表是有界的候选窗口candidateLimit Math.max(take skip, 40) * 2其长度不能代表总数所以 count 通过单独一条 SQL 计算关键词命中 OR 向量列非空的并集见 postgres-search.ts分页选项后置应用distinct、min_score、order、分页都作用于融合后的列表而不是各臂内部见 postgres-search.ts。八、分面、distinct与min_score1. 分面Facets分面查询限定在与主查询相同的命中集范围内统计buildFacetScope复用关键词匹配谓词与过滤器见 postgres-search.ts支持三种类型实现见 utils/facets.tsvalue 分面默认按count DESC, value ASC排序可传limit默认 10与sort: alpha数组字段会先jsonb_array_elements_text展开再分组统计range 分面要求数字字段按from含/to不含区间做COUNT(*) FILTER (WHERE ...)stats 分面要求数字字段返回min、max、avg、sum、count。facetable需要在索引定义中声明facetable: true或对象形式未声明就请求分面会报错。2.distinct去重distinct按字段值去重每个值只保留按请求排序下的第一条命中计数同样生效。实现上使用窗口函数ROW_NUMBER() OVER (PARTITION BY expr ORDER BY ...)包裹一层__rn 1的过滤见 postgres-search.ts。注意数组字段和向量字段不能作为distinct目标resolveDistinct会拒绝见 postgres-search.ts。3.min_score阈值min_score对命中分数做过滤score ?并且保留请求的排序。它和distinct一起使用时会触发executeQuery的包裹wrapped查询路径——把带score列的内层查询包成子查询再在外层做阈值过滤和去重见 postgres-search.ts。九、底层实现文档存储与关键词检索原理1. 文档表结构每个索引对应一张search_pg_physical_name文档表表名规范化逻辑见 utils/plan.ts核心列包括idtext主键——来自文档的primary_key字段documentjsonb——原始文档查询时可attributes_to_retrieve投影返回indexedjsonb——按索引 schema 扁平化、类型强制的过滤/排序视图search_vectortsvector——带权重的全文向量search_texttext——用于pg_trgm相似度检索的纯文本每个向量字段一个v_path的vector(n)列仅 lakebase。表上建立的索引包括search_vector上的 GIN 索引native、search_text上的gin_trgm_opsGIN 索引拼写容错、indexed上的jsonb_path_opsGIN 索引过滤加速以及 lakebase 下的lakebase_ann向量索引建表逻辑见 postgres-search.ts。2. 写入路径upsertDocuments把文档投影成idindexedsearch_textweighted_partsvectors按200 条一批做多行INSERT ... ON CONFLICT (id) DO UPDATE并用RETURNING (xmax 0)区分新增与更新据此增量维护目录表中的document_count见 postgres-search.ts。同一 id 在批内重复时后写覆盖先写。lakebase 下BM25 索引在文档落库后才惰性创建因为 BM25 依赖语料统计。3. 权重与ts_rank索引字段的searchable.weight会被映射到 PostgreSQL 的setweight权重桶见 utils/plan.tsweight 值setweight 标签 3A 2B 1C其余含默认 1D高权重的字段如标题落入更密集的权重桶ts_rank_cd据此让标题命中优先于正文命中。查询时默认对全索引可搜索字段使用预建的search_vector如果指定了attributes_to_search_on子集则用indexed#路径表达式即时构造加权 tsvector见 postgres-search.ts。4. 拼写容错拼写容错走pg_trgm的word_similarity(query, text)——它把查询与文档文本中最匹配的词序列比较长文档不会稀释分数见 utils/extensions.ts。匹配条件为search_vector tsquery OR word_similarity(...) 0.3打分取GREATEST(ts_rank_cd, word_similarity)见 postgres-search.ts。5. 元数据返回search的返回值包含hits可含score需include_score、facets与metadataskip、take、count、query、processing_time_ms其中count可通过options.count none关闭见 postgres-search.ts。十、一个贴近实战的索引定义示例结合仓库集成测试夹具 product-index.ts一个完整的商品索引定义大致如下它覆盖了本 Provider 的主要能力const productIndex { name: product, entity: product, fields: { id: { type: keyword, filterable: true }, title: { type: text, searchable: { weight: 3 }, sortable: true }, handle: { type: keyword, filterable: true }, description: { type: text, searchable: true }, status: { type: keyword, filterable: true, facetable: true }, brand: { type: keyword, filterable: true, facetable: true, sortable: true, }, min_price: { type: float, filterable: true, sortable: true, facetable: { types: [value, range, stats] }, }, sizes: { type: integer, array: true, filterable: true }, created_at: { type: date, filterable: true, sortable: true }, deleted_at: { type: date, filterable: true }, tags: { type: keyword, array: true, filterable: true, facetable: true }, variants: { type: object, array: true, fields: { sku: { type: keyword, searchable: true, filterable: true }, color: { type: keyword, filterable: true, facetable: true }, }, }, }, events: [product.created, product.updated, product.deleted], async consume(event) { // 把领域事件映射为 upsert / delete 动作 }, async *seed({ filters, catchup }) { // 全量重建或增量补数 }, }从中可以总结出几条实用规则文本字段用searchabletrue 或{ weight }声明参与全文检索过滤字段用filterable: true声明$eq/$in/范围等过滤只对声明过的字段生效分面字段用facetable: true或对象声明数值字段才支持 range/stats 分面数组与嵌套对象会被扁平化为带点号路径的叶子字段嵌套数组字段在过滤时同样遵循成员语义。十一、适用范围与限制总结native引擎适合本地开发、自托管以及任意 PostgreSQL 环境开箱即用无需额外扩展迁移脚本会软失败式地尝试启用pg_trgm与unaccentlakebase引擎仅适用于 Medusa Cloud 或提供 Lakebase Search 扩展的 PG16 环境提供 BM25 关键词排序与 ANN 向量/混合检索两种引擎都不支持高亮、geo、游标分页与查询时 locale设计时需要避免在查询中使用这些选项Provider 配置与索引 schema 变更后需重新执行npx medusa db:migrate/npx medusa db:migrate-search索引 schema 变更会通过schema_hash检测并触发文档表重建。深入阅读建议核心服务实现见 services/postgres-search.ts索引规划与引擎校验见 utils/plan.ts过滤编译见 utils/filters.ts分面实现见 utils/facets.ts迁移脚本见 migrations/Migration20260807120000.ts集成测试夹具见 integration-tests/fixtures/product-index.ts。【免费下载链接】medusaThe worlds most flexible commerce platform for agents and developers项目地址: https://gitcode.com/GitHub_Trending/me/medusa创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表