Store.CloudProduct
管道装配阶段(builder.Build() 之后、app.Run() 之前):这里可以挂中间件、解析容器里的服务
按图片阅读顺序返回文字和中文品牌名,无识别项返回空数组。
云商品管理:商品查询、导入、违规上报及搜索索引维护。
获取全部违规原因字典,包含未启用违规判定的原因,按ID升序返回。
批量上报违规商品;重复上报合并原因。
记录已完成的违规上报(1)、自动上货剔除(2)或店铺自动下架(3)。
按店铺编号数组查询违规日志,可筛选商品,按日志编号倒序翻页。
批量解除商品违规,恢复正常商品索引;失败后由后台索引任务重试。
按商品编号批量查询是否违规。
获取服务器当前日期(长日期格式)。
手动执行待处理商品的索引任务。
分页搜索商品,可按标题、价格、类目、销量和平台筛选。
商品筛选条件及分页参数。
符合条件的商品列表及总数。
分词搜索,直接返回索引中的商品摘要(路由保持 SearchGoodsToIds 不变)
导入测试数据:读取 ImportConverters/data.txt 并走完整解析 + 入库 + 分词流程。
导入接口:接收客户端批量上传的 JSON 文件,解析后入库并写入分词索引。
查询 OpenSearch 状态。
检查搜索索引是否存在。
检查索引映射(分析器)是否符合当前服务要求。
创建搜索索引(含 IK 分词映射,已存在且映射正常时跳过)。
删除搜索索引。
手动刷新搜索索引,使最新写入立即可搜索。
手动新增或覆盖一条搜索文档。
读取指定商品详情:解压缩原始数据并返回 JSON。
读取指定商品的原始数据(解压缩后原样返回)。
重新从数据库读取指定商品,覆盖 OpenSearch 已有分词并重新分词。
ids 为空时重建全部商品。
删除商品(按商品编号)。是否软删除由配置 Delete:SoftDelete 决定,
软删除将 Status 置 1,硬删除物理删除记录;两种方式都会删除 OpenSearch 中对应文档。
清空并重建搜索索引(路由保持 ClearSearch 不变)。
统计索引中的文档数(路由保持 GetSearchCount 不变)。
上传图片识别及当前用户的商品安全记录。
上传图片识别及当前用户的商品安全记录。
用户收藏商品:收藏/取消收藏(数据库 + 收藏索引同步)、收藏分组、收藏状态查询、收藏检索与索引重建。
请求中的 userName 允许为空,为空时取当前登录用户。
批量收藏商品:写入 user_goods_favorites 并同步写入收藏索引,返回本次成功收藏的商品数量。
商品已收藏时视为修改收藏分组;商品不存在/已删除的编号会被跳过。
更新用户已收藏商品的安全结论。
批量取消收藏:删除 user_goods_favorites 记录并同步删除收藏索引文档,返回实际取消的条数。
创建收藏分组:创建成功返回 true,同名分组已存在返回 false。
查询用户的收藏分组(含默认分组)及分组下收藏数量。
按 GoodsIds 顺序返回每个商品是否已被收藏(如 [true,false,...]),前台可按顺序直接渲染。
检索用户收藏的商品(标题、销量、价格、类目、分组)。
移除所有用户收藏索引并重新创建,随后按 user_goods_favorites 关联 goods 全量回填。
取用户名:显式传入优先,否则取当前登录用户。
收藏商品请求(支持多选批量收藏)
用户名(为空时取当前登录用户)
商品编号集合(可多选)
收藏分组ID(默认0,表示默认分组;大于0时必须存在且属于该用户)
创建收藏分组请求
用户名(为空时取当前登录用户)
分组名
导入项:商品模型 + 原始数据
解析后的商品模型
原始数据(JSON 原文,压缩后落盘)
商品导入结果
成功条数
失败条数
总条数
错误明细
商品搜索文档:OpenSearch 索引中的商品模型,Id 为主键,Title 用于分词搜索
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低价快照,用于价格区间过滤和按价格排序
销量,用于按销量排序
商品搜索请求
标题(模糊搜索)
最低价格(分)
最高价格(分)
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低销量
最高销量
平台类型
页码(默认1)
每页数量(默认20)
排序字段
排序方式:asc/desc(默认desc)
原因名称,例如“出售假冒商品”;新名称默认仅记录字典,不判定违规。
存在违规记录且已完成索引下架时为 true,否则为 false。
当前商品命中的违规原因,供客户端记录实际处理动作。
商品不存在、已删除或恢复期间再次被上报违规的编号。
日志记录的实际业务动作,与商品违规原因分别保存。
客户端在店铺动作完成后提交一条日志。
违规类型在 violation_reason 中的编号。
按商铺编号查询违规日志;翻页时传入上一页最后一条日志的编号。
单张商品图片,使用 multipart/form-data 上传。
客户端指定的 32 位十六进制 MD5 缓存键,大小写均可。
图片原始字节的 Base64 字符串,不含 Data URL 前缀。
OpenSearch 运行状态
节点地址
索引名称
是否可连接
OpenSearch 服务及目标索引是否健康
集群名称
集群状态(green、yellow 或 red)
集群节点总数
数据节点数量
活跃主分片数量
活跃分片总数
正在迁移的分片数量
正在初始化的分片数量
未分配的分片数量
索引是否存在
索引映射是否符合当前服务要求
标题字段的索引分析器
标题字段的搜索分析器
文档总数(索引不存在或读取失败时为 -1)
状态检测耗时(毫秒)
状态说明或错误信息
取消收藏(批量)请求
用户名(为空时取当前登录用户)
要取消收藏的商品编号集合
保存收藏商品的检测结论,沿用原接口的字符串商品编号。
用户收藏分组
分组ID
用户名
分组名
该分组下的收藏数量
用户收藏商品(索引文档回显模型)
收藏记录自增主键
用户名
收藏分组ID(0 表示默认分组)
收藏分组名
商品编号
平台类型
商品标题
缩略图
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低价快照(分)
销量
收藏时间
安全检测
用户收藏商品搜索文档:OpenSearch 索引中的收藏模型。
一条收藏记录 = 用户 + 商品快照(标题/价格/销量/类目)+ 收藏分组,
文档 Id 固定为 "{user_name}:{goods_id}"(表 uk_user_goods 保证唯一),便于收藏/取消收藏时幂等覆盖与删除。
安全检测结论;为空表示尚未检测。
文档主键(同时作为 OpenSearch 的 _id):{user_name}:{goods_id}
收藏记录自增主键(user_goods_favorites.id)
用户名(收藏归属人,检索时强制过滤)
收藏分组ID(0 表示默认分组)
收藏分组名(分组ID为0时为默认分组名)
商品编号
平台类型(1 PDD、2 WX)
商品标题,用于分词搜索
缩略图
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低价快照(分),用于价格区间过滤和按价格排序
销量,用于按销量排序
收藏时间,默认按此字段倒序
生成文档主键:{user_name}:{goods_id}
用户收藏商品搜索请求(仅检索当前用户自己的收藏)
安全状态:0 全部(默认),1 安全,2 违规,3 未检测。
用户名(为空时取当前登录用户)
标题关键字(分词模糊搜索)
收藏分组ID(0 表示默认分组)
收藏分组名(与分组ID二选一,同时传入时以分组ID为准)
最低价格(分)
最高价格(分)
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低销量
最高销量
平台类型
页码(默认1)
每页数量(默认20)
排序方式:CreatedTimeDesc(默认,收藏时间倒序)/ CreatedTimeAsc / PriceAsc / PriceDesc / SoldDesc
查询商品是否已被收藏请求:按 GoodsIds 顺序返回是否已收藏
用户名(为空时取当前登录用户)
商品编号集合
商品表实体(对应数据库表 goods)
自增ID
平台类型
1 PDD
商品编号
标题
描述
缩略图
一级类目ID
二级类目ID
三级类目ID
四级类目ID
最低价快照(元),导入时计算
最高价快照(元),导入时计算
销量
状态:0正常 1已删除
创建时间
更新时间(自动更新)
是否已分词:0未 1已
不可变的违规事件历史,解除商品违规时保留。
对应 violation_reason.id。
跨用户复用的图片识别数据,仅存储成功识别结果。
客户端指定的 MD5 缓存键,统一保存为 32 位小写十六进制。
模型识别结果的 JSON 字符串数组,空数组表示未识别到文字或品牌。
缓存最近更新时间,UTC。
用户收藏商品表实体(对应数据库表 user_goods_favorites)
自增主键
用户名(同一用户不能重复收藏同一商品)
收藏分组ID(0 表示默认分组),对应 user_goods_favorites_group.id
商品编号,对应 goods.goods_id
最近上报的安全结论,null 表示尚未检测。
收藏时间
用户收藏分组表实体(对应数据库表 user_goods_favorites_group)
自增主键,即收藏表 user_goods_favorites.group_id 的取值
用户名
分组名
搜索排序方式
相关性(默认)
价格从低到高
价格从高到低
销量从高到低
用户收藏商品搜索排序方式
按收藏时间倒序(默认)
按收藏时间正序
价格从低到高
价格从高到低
销量从高到低
导入商品数据转换器
原始数据(JSON 原文)
获取转换器名称
支持的平台类型
读取内容
JSON 原文内容
判断是否匹配当前转换器
是否匹配
转换为标准商品模型
转换器基类:统一实现读取、校验与转换骨架,子类只需实现匹配判定与字段映射。
由子类实现的具体匹配判定
带校验的转换(基类统一实现)
由子类实现的具体字段映射
导入商品转换工厂:按顺序尝试各转换器,返回标准商品模型。
根据本地 JSON 文件路径转换。
根据 JSON 内容字符串转换。
PDD 前端商品详情数据转换器(数据源格式见 data.txt)
计算价格区间。优先使用顶层 price 节点,其次遍历 sku。
商品仓储(对应 goods 表)
用户收藏分组仓储(对应 user_goods_favorites_group 表)
用户收藏商品仓储(对应 user_goods_favorites 表)
查询搜索服务状态;网络不可用时记录错误,不阻止 HTTP 服务启动。
查询搜索服务状态;网络不可用时记录错误,不阻止 HTTP 服务启动。
Hangfire 定时任务:把数据库中未同步(IndexStatus=0)的商品写入 OpenSearch 分词索引。
跨实例串行化违规上报和商品索引写入,防止下架后被旧批次写回。
跨实例串行化违规上报和商品索引写入,防止下架后被旧批次写回。
收藏重建、整条文档写入和安全状态更新共用独立锁,防止旧快照覆盖新结论。
批量导入商品:先落库(按平台 + 商品编号去重)+ 保存原始数据,
然后根据配置决定“立即分词”还是“标记未同步交给后台任务分词”。
后台任务:批量处理未同步(IsSegmented=0)的商品,写入 OpenSearch 后标记为已同步。
按平台 + 商品编号查找已存在记录,存在则更新,不存在则新增。
根据商品编号(GoodsId)列表读取商品。
重新从数据库读取指定商品,覆盖 OpenSearch 中已有的分词并重新分词。
ids 为空时重建全部商品。重建成功的记录标记为已同步。
删除商品:按配置决定软删除(Status=1)还是硬删除(物理删除),
两种方式都会删除 OpenSearch 中对应的文档。
批量更新商品缩略图。
是否导入时立即分词(Indexing:Mode = Immediate)。
是否软删除(Delete:SoftDelete,默认 true)。
违规商品搜索索引清理任务,由 CloudProductPlugin 注册为每分钟执行一次。
每批处理最多 1000 个尚未完成索引删除的违规商品,循环处理至无待处理记录。
违规商品搜索索引清理任务,由 CloudProductPlugin 注册为每分钟执行一次。
每批处理最多 1000 个尚未完成索引删除的违规商品,循环处理至无待处理记录。
删除待处理商品的 OpenSearch 索引,成功后将违规记录的 IsIndexDeleted 标记为 true。
失败时异常交由 Hangfire 处理,尚未标记完成的记录留待后续执行继续处理。
整批校验后统一写入日志,每个事件保留一条记录。
分页读取违规事件,beforeId 为上一页最后一条日志编号。
============ 1. 创建索引 ============
============ 2. 删除索引 ============
============ 3.1 批量写入商品搜索文档(存在则覆盖) ============
============ 3.2 根据数据库商品重建搜索索引 ============
============ 3.3 按商品编号批量删除 OpenSearch 文档(软/硬删除共用) ============
============ 4. 手动新增一条搜索文档 ============
============ 5. 分词搜索(分页 + 类目/价格/销量/平台过滤 + 排序) ============
搜索条件(关键词、类目、价格、销量、平台、分页)
排序方式
============ 6. 统计文档数 ============
============ 7. 查询 OpenSearch 状态 ============
清空索引:删除后按统一映射重建,重建期间该索引不可查(由后台定时任务负责回填数据,接受短暂空窗)
商品检测业务入口,负责上传图片识别、MD5 缓存和当前用户的商品安全记录。
商品检测业务入口,负责上传图片识别、MD5 缓存和当前用户的商品安全记录。
通过千问兼容接口识别上传图片中的文字及品牌。
按插件配置创建并复用模型客户端,定期更新池内连接以跟随 DNS 变化。
商品原始数据文件存储:按 goodsId % 100 分目录,文件名即商品ID,GZip 压缩保存。
保存原始数据,返回保存后的完整路径。
读取并解压原始数据;文件不存在时返回 null。
判断指定商品的原始数据文件是否存在。
用户收藏商品索引服务:负责收藏索引(Search:FavoritesIndexName)的
创建、写入、删除、重建与检索,索引文档由 user_goods_favorites 关联 goods 补全而来。
检查索引是否存在
检查索引映射(分析器)是否符合当前服务要求
创建索引(含 IK 分词映射;已存在且映射正常时跳过)
删除并重建索引(映射统一,重建期间该索引不可查)
批量写入收藏文档(存在则覆盖)
更新单条收藏的安全字段并等待对检索可见。
按文档Id批量删除收藏文档
统计索引文档数
按用户检索收藏商品(标题/销量/价格/类目/分组)
============ 1. 索引是否存在 ============
============ 2. 索引映射是否健康 ============
============ 3. 创建索引 ============
============ 4. 删除并重建索引 ============
============ 5. 批量写入收藏文档(存在则覆盖) ============
============ 6. 按文档Id批量删除收藏文档 ============
============ 7. 统计文档数 ============
============ 8. 检索用户收藏商品(标题/价格/销量/类目/分组 + 排序 + 分页) ============
用户收藏商品业务:收藏/取消收藏(数据库 + 收藏索引同步写入)、收藏分组维护、收藏状态查询、收藏检索与索引重建。
批量收藏商品,返回本次成功收藏的商品数量(已收藏的商品视为修改收藏分组)
按用户和商品编号更新已存在的收藏记录。
批量取消收藏,返回实际取消的条数
创建收藏分组:创建成功返回 true,同名分组已存在返回 false
查询用户的收藏分组(含默认分组)及分组下收藏数量
按 GoodsIds 顺序返回每个商品是否已被该用户收藏
检索用户收藏的商品(标题/销量/价格/类目/分组)
移除所有用户收藏索引并按数据库数据全量重建,返回重建的文档数
未归属任何分组的收藏所使用的分组名(对应 group_id = 0)
重建索引时单次 bulk 的文档数,避免一次请求过大
批量收藏商品:先落库(user_goods_favorites),再同步写入收藏索引;
商品不存在/已删除的编号会被跳过,返回本次成功收藏的商品数量。
任意一步失败都会回滚本次已写入的数据库记录,保证“数据库中有收藏 = 索引中可搜索到”。
仅修改安全字段,避免覆盖同时发生的收藏分组变更。
批量取消收藏:先删除数据库记录,再删除索引文档;
索引删除失败时回补数据库记录,避免“库里有收藏但搜索不到”。
创建收藏分组:创建成功返回 true,同一用户同名分组已存在返回 false。
查询用户的收藏分组及分组下收藏数量,默认分组(分组ID=0)存在收藏时一并返回。
按 GoodsIds 顺序返回每个商品是否已被该用户收藏(商品编号无效的返回 false)。
以数据库为准,不依赖索引,索引重建期间结果依然准确。
从收藏索引检索当前用户的收藏商品。
移除所有用户收藏索引并重新创建,然后从 user_goods_favorites 关联 goods 全量回填。
收藏落库成功但索引写入失败时的补偿:撤销本次新增的收藏记录、还原被修改的收藏分组。
取分组名:分组ID <= 0 返回默认分组名,分组不存在返回空串。
组装收藏索引文档:收藏记录 + 商品快照 + 分组名。
解析排序方式,非法值一律按“收藏时间倒序”处理。
Generates a documentation comment ID for a type.
Example: T:Namespace.Outer+Inner`1 becomes T:Namespace.Outer.Inner`1
Generates a documentation comment ID for a property.
Example: P:Namespace.ContainingType.PropertyName or for an indexer P:Namespace.ContainingType.Item(System.Int32)
Generates a documentation comment ID for a property given its container type and property name.
Example: P:Namespace.ContainingType.PropertyName
Generates a documentation comment ID for a method (or constructor).
For example:
M:Namespace.ContainingType.MethodName(ParamType1,ParamType2)~ReturnType
M:Namespace.ContainingType.#ctor(ParamType)
Generates a documentation ID string for a type.
This method handles nested types (replacing '+' with '.'),
generic types, arrays, pointers, by-ref types, and generic parameters.
The flag controls whether
constructed generic type arguments are emitted, while
controls whether the generic arity marker (e.g. "`1") is appended.
Normalizes a documentation comment ID to match the compiler-style format.
Strips the return type suffix for ordinary methods but retains it for conversion operators.
The documentation comment ID to normalize.
The normalized documentation comment ID.
A special attribute recognized by Roslyn, that marks a type as "embedded", meaning it won't ever be visible from other assemblies.