diff --git a/docs/索引spu-sku层级结构设计.md b/docs/索引spu-sku层级结构设计.md deleted file mode 100644 index a1c5f85..0000000 --- a/docs/索引spu-sku层级结构设计.md +++ /dev/null @@ -1,388 +0,0 @@ - - -公司文档地址:https://www.kdocs.cn/l/cav0b2rdk42n?from=docs&startTime=1763618428738&createDirect=true&newFile=true -飞书地址:https://xp0y6kmku6.feishu.cn/wiki/ToYTwpjkViqPkZkcOz7cTZopnyc - -SPU-SKU索引方案选型 -1. SKU为单位 + Collapse + inner_hits -1. 优点: -1. sku评分精准 (SKU 级别评分。如果sku影响相关性较多) -2. 可扩展性:如果以后需要返回sku级别结果,索引改动小。 -3. 索引更新灵活,单个sku字段变化只会引起单个sku的更新。 -2. 缺点: -1. inner_hits性能很差 -2. spu级别的查询字段冗余,冗余倍数跟spu下面平均sku数量线性相关 -3. 方案介绍 -1. 查询性能: - a. 主查询执行(召回结果)(比如5000sku) → collapse折叠(按spu_id分组、每组选top文档,比如得到1000sku) → 排序、按spu排序截取分页内结果(比如100) → 执行inner_hits (获取 spu内sku,相当于执行 page_size 次子查询) - b. collapse阶段的耗时影响因素: - i. 召回数量 、 基数(Cardinality)(去重后的spu数量,高基数字段collapse性能差)。 - c. Inter hits(主要开销来源): - i. 取决于分页size。(相当于page_size次子查询,"max_concurrent_group_searches"限制并发组查询) - ii. 我们在宜采的实践,分页size=100的情况下,Inter hits开销非常大(Inter hits size = 4,只取id 不取任何sku字段、按原始打分排序) - d. Inner hits 为什么性能差? - i. 不对分桶内结果进行一次排序就行了吗?一个for循环的事情,为什么要用max_concurrent_group_searches线程去并发? - ii. Collapse 阶段只保留每个分组的最佳文档,其他文档被丢弃。 - iii. Collapse 阶段:每个分片独立执行collapse、最后协调节点做全局collapse。 - iv. Inner_hits 阶段:每个spu下的sku可能在多个分片上,因此需要跨分片查询。 - v. ES为什么要在collapse阶段丢弃其他文档: - 1. 我的理解是,ES可能认为多数时候不需要inner_hits。Lazy Loading。对需要inner_hits的场景很不友好。 - e. 即使collapse阶段只保留了最佳文档,为什么inner_hits阶段 为什么做page_size 100次查询、而不是做一次查询:spu_id in [1, 2, 3, ... 100个 ] AND (原始查询条件) 。 我们宜采的搜索就是这么做的。 -阶段1:主查询 + Collapse -├─ 每个分片执行查询 -├─ 每个分片执行 collapse(只保留最高分文档) -├─ 协调节点合并分片结果 -└─ 输出:1000 个 SPU(每个只有 1 个 SKU) - -阶段2:Inner_hits(只对需要返回的分组执行) -├─ 输入:100 个 SPU(size=100) -├─ 对每个 SPU 执行查询: -│ ├─ 构建查询:spu_id=123 AND (原始查询条件) -│ ├─ 发送到所有分片 -│ ├─ 等待分片响应 -│ ├─ 合并分片结果 -│ └─ 排序和截取(size=3) -└─ 输出:100 个 SPU,每个有 3 个 SKU,按要求排序和填充2. 索引: - a. 缺点:spu级别的查询字段冗余。比如1个spu下面有2*5个款式,那么 spu_title brielf description seo_keywords cate tags vendor 这些 spu 字段 将被重建10次索引。 - b. 优点:索引更新灵活,单个sku字段变化只会引起单个sku的更新。 -4. 参考资料 -1. [Collapse search results](https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html) - collapse 在每个分片上独立执行,每个分片为每个折叠键选择代表文档,协调节点merge最佳文档 -2. [Retrieve inner hits](https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html) 每个折叠结果会触发额外的查询。 -5. 适用场景: -sku级别的字段对打分影响较大,搜索需要重点关注 sku级别的title、属性的匹配情况。 -需要关注spu内部sku排序。 -6. 跟我们的适配情况: -1. 我们的 款式 多数情况并不影响搜索结果。 - a. 相关性影响最重的 基本都在spu :spu_title brielf description seo_keywords cate tags vendor - b. 款式:需要参与(甚至可以不参与)排序,但是对相关性影响很小 -2. 款式 - a. 笛卡尔积,variants多,冗余情况较严重 -3. inner_hits的includes字段:我们可以只要ID,也就是只返回spu级别字段。 - a. sku级别字段点击详情页再触发。 - b. 如果需要sku级别字段,也可以将其作为spu的属性字段进行返回,而不用从inner_hits的includes获取。 -4. 我们的 inner_hits 可能需要更多的source字段 -2. SKU为单位 + Collapse 获得spu级别排序(不执行inner_hits) -没有inner_hits的性能问题,但是仍然有 spu级别检索字段 冗余的问题。 -3. spu为单位。SKU字段展开作为SPU属性 -1. 索引方案 -sku的title作为spu 的sku_titles 属性。 -款式字段同样展开,作为 sku 的 list 属性。 -除了title, brielf description seo相关 cate tags vendor所有影响相关性的字段都在spu。 sku只有一个title。所以,可以以spu为单位,sku的title作为spu的一个字段,以list形式灌入,假设一个spu有三个sku,那么这个sku_titles字段有三个值,打分的时候按max取得打分。 -# 写入 spu 级别索引 -def build_product_document(product, variants): - return { - "product_id": str(product.id), - "title": product.title, - - # Variant搜索字段(展开) - "variant_titles": [v.title for v in variants], - "variant_attributes": self._extract_all_attributes(variants), - - # Variant详细信息(用于返回) - "variants": [ - { - "id": str(v.id), - "title": v.title, - "price": float(v.price), - "options": v.options - } - for v in variants - ], - - # titles参与相关性计算 - "titles": list(set([v.title for v in variants if v.title])), - - # 属性字段(扁平化,用于过滤) - "option1": list(set([v.option1 for v in variants if v.option1])), - "sizes": list(set([v.option2 for v in variants if v.option2])), - - "min_price": min(v.price for v in variants), - "max_price": max(v.price for v in variants) - }2. 查询方案 -对数组字段使用 dis_max,只取最高分,避免累加。 -3. 问题 -不好得到每个子title的得分以决定sku的排序。方案: -1. 打开explain,会影响性能,不推荐。(只需要记下来sku_titles 中每一项的打分,但是打开explain会记录太多的东西) -2. 修改ES,把 sku_titles 数组中 每个title的匹配得分记下来。 -3. 对返回的结果的子sku根据title和属性的匹配情况再做一次匹配,以决定sku的排序。 -4. sku 作为nested -如果需要查询nested字段,会需要nested join,本质是是父子文档的join。 -性能影响因子:- 子文档数量:线性增长,每个SKU增加约 5-15ms 查询时间- 嵌套深度:指数增长,多级嵌套性能急剧下降- 查询复杂度:nested bool查询比普通查询慢 3-10倍 -原因: -1. 内部 Join 操作:ES 为每个 nested 对象创建隐藏文档,查询时需要 join -2. 文档膨胀:1个SPU文档实际存储为 1+N 个文档(N=SKU数量) -3. 内存开销:nested 查询需要加载所有匹配的父子文档到内存 -适用场景: -• 查询模式简单(主要是过滤,少用复杂评分) -5. Spu sku 独立索引 -spu-catalog-*:用于品牌、类目、商品介绍等宏观搜索。包括列表页搜索。 -sku-catalog-*:用于具体规格搜索、下单。涉及到价格、库存筛选的查询。 - -两者各有各的字段: -SPU索引: -├─ 数据:品牌、类目、描述、SEO信息 -├─ 更新频率:低(几天一次) -├─ 查询场景:列表页、品牌搜索、类目浏览 -└─ 优化方向:文本搜索、相关性排序 - -SKU索引: -├─ 数据:规格、价格、库存 -├─ 更新频率:高(实时更新) -├─ 查询场景:详情页、规格筛选、价格排序 -└─ 优化方向:精确匹配、数值范围查询 -联合查询:使用 multi_search 或应用层合并 - -这种场景的效果 可以等同于 sku 作为nested方案,如果 sku 的nested字段,只有数值型的用于查询,其他的的只用于返回填充。 - -店匠商家SPU-SKU数据情况调研 -商品(product)的多款式(variants)配置 -3种属性/款式,是笛卡尔积的形式生成variants(sku) -服装领域的多款式 -服装领域,variants(sku)基本上都是 颜色、size。 -size 基本上每个商品都有: -XS S M L XL 3XL,有的还有4XL,5XL -颜色: blue/orange/purple/green... -款式:dress1 dress2 shirt1 shirt2 swimsuit1 set1 set2... - -当前的多数独立站多款式是否参与搜索 -看起来搜索的索引粒度是spu单位的。 query加上sku相关信息,并不会让sku在spu内更靠前 - -下面的几个案例,都是我用 spu名称 + 其中一款的款式名称 进行搜索,看召回的spu 是否会将我指定的款式前置。 可以看到不管我是否加款式限定,返回结果的每个spu下的子sku顺序都不会受影响。 - - - - - -SPU-SKU索引建议方案 -spu为单位。SKU字段展开作为SPU属性 -其他重点字段 -1. Sku title -2. category -1. 数据源 -2. Mysql -在spu表中: -Field Type -category varchar(255) -category_id bigint(20) -category_google_id bigint(20) -category_level int(11) -category_path varchar(500) -3. ES索引 -1. 输入数据 - 设计 1,2,3级分类 三个字段,的 category (原始文本) -2. 索引方法 - 设计要求: -1. 支持facet(精确过滤、keyword聚合),并且性能需要足够高。 -2. 支持普通搜索模糊匹配(用户原始query可能包括分类词)。 -3. 模糊匹配要考虑多语言 -方案:采用方案2 -4. categoryPath索引 + Prefix 查询(categoryPath.keyword: "服装/男装")(如果满足条件的key太多的则性能较差,比如 查询的是一级类目,类目树叶子节点太多时性能较差) -5. categoryPath支撑模糊查询 和 多级cate keyword索引支撑精确查询。 索引阶段冗余,查询性能高。 - "category_path_zh": { // 提供模糊查询功能,辅助相关性计算 - "type": "text", - "analyzer": "hanlp_index", - "search_analyzer": "hanlp_standard" - }, - "category_path_en": { // 提供模糊查询功能,辅助相关性计算 - "type": "text", - "analyzer": "english", - "search_analyzer": "english" - }, - "category_path": { // 用于多层级的筛选、精确匹配 - "type": "keyword", - "normalizer": "lowercase" - }, - "category_id": { - "type": "keyword" - }, - "category_name": { - "type": "keyword" - }, - "category_level": { - "type": "integer" - }, - "category1_name": { // 不同层级下 可能有同名的情况,因此提供一二三级分开的查询方式 - "type": "keyword" - }, - "category2_name": { - "type": "keyword" - }, - "category3_name": { - "type": "keyword" - }, -3. tags - -1. 数据源 -多值 -标签 - -最多输入250个标签,每个不得超过500字符,多个标签请用「英文逗号」隔开 - -新品,热卖,爆款 - -耳机,头戴式,爆款 - -分割后 list形式灌入 -2. Mysql -3. ES索引 -1. 输入数据 -2. 索引方法 -4. 供应商 -1. 数据源 -2. Mysql -3. ES索引 -1. 输入数据 -2. 索引方法 -5. 款式/选项值(options) -1. 数据源 -以下区域字段,商品属性为M(商品主体)的行需填写款式名称,商品属性为P(子款式)的行需填写款式值信息,商品属性为S(单一款式商品)的行无需填写 - -款式1 -款式2 -款式3 - -最多255字符 -最多255字符 -最多255字符 - -SIZE -COLOR - - -S -red - - -S -black - - -S -army - - -L -red - - -L -black - - -L -army - - -XL -red - - -XL -black - - -XL -army - - -2. Mysql -1. API 在 SPU 的维度直接返回3个属性定义,存储在 shoplazza_product_option 中: -2. API在 SKU的维度直接返回3个属性值,存储在 shoplazza_product_sku 表的 option 相关的字段中: -3. ES索引 -1. 输入数据 -2. 索引方法 - 1)铺平展开,只支持三个,支持查询。缺点是,查询逻辑跟租户的属性维度绑定,不灵活 - attr1 - attr2 - attr3 - option1 - option2 - option3 - 2)nested,支持超过3个属性(动态)。支持查询 - "specifications": { - "type": "nested", - "properties": { - "name": { "type": "keyword" }, // "颜色", "容量" - "value": { "type": "keyword" } // "白色", "256GB" - } - }, - 3)nested,支持超过3个属性(动态)。只用作返回,不能查询。节省索引空间 - "specifications": { - "type": "nested", - "properties": { - "name": { "type": "keyword","index": false }, - "value": { "type": "keyword","index": false } - } - }, - - TODO 考虑使用方案(3)。 -6. SEO相关字段 -1. 数据源 -SEO标题 -SEO描述 -SEO URL Handle -SEO URL 重定向 -SEO关键词 - -最多5000字符 -最多5000字符 -最多支持输入255字符 - (SEO URL handle只对SEO URL的「URL参数」部分进行更改,即“products/”后的内容,如:products/「URL参数」 - ) -创建URL重定向,访问修改前链接可跳转到修改后的新链接页面 -「Y」:TRUE -「N」:FALSE -多个关键词请用「英文逗号」隔开 - - -2. Mysql -3. ES索引 -1. 输入数据 -2. 索引方法 -7. 供应商 -1. 数据源 -供应商名称 -供应商URL - -最多20字符 -请输入供应商URL - -Amazon -https://www.amazon.com/Legendary-Whitetails-Buck-Flannels-Large/dp/B01KTUMBOI/ref=sr_1_1?s=fashion-mens-intl-ship&ie=UTF8&qid=1543038722&sr=1-1 - -2. Mysql - -3. ES索引 -1. 输入数据 -2. 索引方法 -8. 其他 -1. 数据源 -2. Mysql -3. ES索引 -1. 输入数据 -2. 索引方法 -索引整体配置 -常用查询域(Query Domains) -1. default(默认索引): 搜索所有文本字段 - a. 包含字段:title, sku_titles(TODO), brief, description, seo_title(TODO待确认), seo_keywords, vendor, category_path, tags, category (带具体的语言后缀) -2. title(标题索引): 仅搜索标题相关字段 - a. 包含字段:title, sku_titles, seo_title (带具体的语言后缀) -3. vendor(品牌索引): 仅搜索品牌字段 - a. 包含字段:vendor (带具体的语言后缀) -4. category_path(类目索引): 仅搜索类目字段 - a. 包含字段:category_path(带具体的语言后缀) -5. tags(标签索引): 搜索标签和SEO关键词 - a. 包含字段:tags, seo_keywords -提权字段 -function_score -具体提权字段、权重待定(配置化) -"function_score": { - "functions": [ - { "field_value_factor": { "field": "sales_count", "factor": 0.001, "modifier": "log1p" } }, - { "gauss": { "listed_at": { "scale": "30d" } } } - ], - "boost_mode": "multiply" -}facet -分类 -tags - diff --git a/docs/索引方案.md b/docs/索引方案.md new file mode 100644 index 0000000..a1c5f85 --- /dev/null +++ b/docs/索引方案.md @@ -0,0 +1,388 @@ + + +公司文档地址:https://www.kdocs.cn/l/cav0b2rdk42n?from=docs&startTime=1763618428738&createDirect=true&newFile=true +飞书地址:https://xp0y6kmku6.feishu.cn/wiki/ToYTwpjkViqPkZkcOz7cTZopnyc + +SPU-SKU索引方案选型 +1. SKU为单位 + Collapse + inner_hits +1. 优点: +1. sku评分精准 (SKU 级别评分。如果sku影响相关性较多) +2. 可扩展性:如果以后需要返回sku级别结果,索引改动小。 +3. 索引更新灵活,单个sku字段变化只会引起单个sku的更新。 +2. 缺点: +1. inner_hits性能很差 +2. spu级别的查询字段冗余,冗余倍数跟spu下面平均sku数量线性相关 +3. 方案介绍 +1. 查询性能: + a. 主查询执行(召回结果)(比如5000sku) → collapse折叠(按spu_id分组、每组选top文档,比如得到1000sku) → 排序、按spu排序截取分页内结果(比如100) → 执行inner_hits (获取 spu内sku,相当于执行 page_size 次子查询) + b. collapse阶段的耗时影响因素: + i. 召回数量 、 基数(Cardinality)(去重后的spu数量,高基数字段collapse性能差)。 + c. Inter hits(主要开销来源): + i. 取决于分页size。(相当于page_size次子查询,"max_concurrent_group_searches"限制并发组查询) + ii. 我们在宜采的实践,分页size=100的情况下,Inter hits开销非常大(Inter hits size = 4,只取id 不取任何sku字段、按原始打分排序) + d. Inner hits 为什么性能差? + i. 不对分桶内结果进行一次排序就行了吗?一个for循环的事情,为什么要用max_concurrent_group_searches线程去并发? + ii. Collapse 阶段只保留每个分组的最佳文档,其他文档被丢弃。 + iii. Collapse 阶段:每个分片独立执行collapse、最后协调节点做全局collapse。 + iv. Inner_hits 阶段:每个spu下的sku可能在多个分片上,因此需要跨分片查询。 + v. ES为什么要在collapse阶段丢弃其他文档: + 1. 我的理解是,ES可能认为多数时候不需要inner_hits。Lazy Loading。对需要inner_hits的场景很不友好。 + e. 即使collapse阶段只保留了最佳文档,为什么inner_hits阶段 为什么做page_size 100次查询、而不是做一次查询:spu_id in [1, 2, 3, ... 100个 ] AND (原始查询条件) 。 我们宜采的搜索就是这么做的。 +阶段1:主查询 + Collapse +├─ 每个分片执行查询 +├─ 每个分片执行 collapse(只保留最高分文档) +├─ 协调节点合并分片结果 +└─ 输出:1000 个 SPU(每个只有 1 个 SKU) + +阶段2:Inner_hits(只对需要返回的分组执行) +├─ 输入:100 个 SPU(size=100) +├─ 对每个 SPU 执行查询: +│ ├─ 构建查询:spu_id=123 AND (原始查询条件) +│ ├─ 发送到所有分片 +│ ├─ 等待分片响应 +│ ├─ 合并分片结果 +│ └─ 排序和截取(size=3) +└─ 输出:100 个 SPU,每个有 3 个 SKU,按要求排序和填充2. 索引: + a. 缺点:spu级别的查询字段冗余。比如1个spu下面有2*5个款式,那么 spu_title brielf description seo_keywords cate tags vendor 这些 spu 字段 将被重建10次索引。 + b. 优点:索引更新灵活,单个sku字段变化只会引起单个sku的更新。 +4. 参考资料 +1. [Collapse search results](https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html) - collapse 在每个分片上独立执行,每个分片为每个折叠键选择代表文档,协调节点merge最佳文档 +2. [Retrieve inner hits](https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html) 每个折叠结果会触发额外的查询。 +5. 适用场景: +sku级别的字段对打分影响较大,搜索需要重点关注 sku级别的title、属性的匹配情况。 +需要关注spu内部sku排序。 +6. 跟我们的适配情况: +1. 我们的 款式 多数情况并不影响搜索结果。 + a. 相关性影响最重的 基本都在spu :spu_title brielf description seo_keywords cate tags vendor + b. 款式:需要参与(甚至可以不参与)排序,但是对相关性影响很小 +2. 款式 + a. 笛卡尔积,variants多,冗余情况较严重 +3. inner_hits的includes字段:我们可以只要ID,也就是只返回spu级别字段。 + a. sku级别字段点击详情页再触发。 + b. 如果需要sku级别字段,也可以将其作为spu的属性字段进行返回,而不用从inner_hits的includes获取。 +4. 我们的 inner_hits 可能需要更多的source字段 +2. SKU为单位 + Collapse 获得spu级别排序(不执行inner_hits) +没有inner_hits的性能问题,但是仍然有 spu级别检索字段 冗余的问题。 +3. spu为单位。SKU字段展开作为SPU属性 +1. 索引方案 +sku的title作为spu 的sku_titles 属性。 +款式字段同样展开,作为 sku 的 list 属性。 +除了title, brielf description seo相关 cate tags vendor所有影响相关性的字段都在spu。 sku只有一个title。所以,可以以spu为单位,sku的title作为spu的一个字段,以list形式灌入,假设一个spu有三个sku,那么这个sku_titles字段有三个值,打分的时候按max取得打分。 +# 写入 spu 级别索引 +def build_product_document(product, variants): + return { + "product_id": str(product.id), + "title": product.title, + + # Variant搜索字段(展开) + "variant_titles": [v.title for v in variants], + "variant_attributes": self._extract_all_attributes(variants), + + # Variant详细信息(用于返回) + "variants": [ + { + "id": str(v.id), + "title": v.title, + "price": float(v.price), + "options": v.options + } + for v in variants + ], + + # titles参与相关性计算 + "titles": list(set([v.title for v in variants if v.title])), + + # 属性字段(扁平化,用于过滤) + "option1": list(set([v.option1 for v in variants if v.option1])), + "sizes": list(set([v.option2 for v in variants if v.option2])), + + "min_price": min(v.price for v in variants), + "max_price": max(v.price for v in variants) + }2. 查询方案 +对数组字段使用 dis_max,只取最高分,避免累加。 +3. 问题 +不好得到每个子title的得分以决定sku的排序。方案: +1. 打开explain,会影响性能,不推荐。(只需要记下来sku_titles 中每一项的打分,但是打开explain会记录太多的东西) +2. 修改ES,把 sku_titles 数组中 每个title的匹配得分记下来。 +3. 对返回的结果的子sku根据title和属性的匹配情况再做一次匹配,以决定sku的排序。 +4. sku 作为nested +如果需要查询nested字段,会需要nested join,本质是是父子文档的join。 +性能影响因子:- 子文档数量:线性增长,每个SKU增加约 5-15ms 查询时间- 嵌套深度:指数增长,多级嵌套性能急剧下降- 查询复杂度:nested bool查询比普通查询慢 3-10倍 +原因: +1. 内部 Join 操作:ES 为每个 nested 对象创建隐藏文档,查询时需要 join +2. 文档膨胀:1个SPU文档实际存储为 1+N 个文档(N=SKU数量) +3. 内存开销:nested 查询需要加载所有匹配的父子文档到内存 +适用场景: +• 查询模式简单(主要是过滤,少用复杂评分) +5. Spu sku 独立索引 +spu-catalog-*:用于品牌、类目、商品介绍等宏观搜索。包括列表页搜索。 +sku-catalog-*:用于具体规格搜索、下单。涉及到价格、库存筛选的查询。 + +两者各有各的字段: +SPU索引: +├─ 数据:品牌、类目、描述、SEO信息 +├─ 更新频率:低(几天一次) +├─ 查询场景:列表页、品牌搜索、类目浏览 +└─ 优化方向:文本搜索、相关性排序 + +SKU索引: +├─ 数据:规格、价格、库存 +├─ 更新频率:高(实时更新) +├─ 查询场景:详情页、规格筛选、价格排序 +└─ 优化方向:精确匹配、数值范围查询 +联合查询:使用 multi_search 或应用层合并 + +这种场景的效果 可以等同于 sku 作为nested方案,如果 sku 的nested字段,只有数值型的用于查询,其他的的只用于返回填充。 + +店匠商家SPU-SKU数据情况调研 +商品(product)的多款式(variants)配置 +3种属性/款式,是笛卡尔积的形式生成variants(sku) +服装领域的多款式 +服装领域,variants(sku)基本上都是 颜色、size。 +size 基本上每个商品都有: +XS S M L XL 3XL,有的还有4XL,5XL +颜色: blue/orange/purple/green... +款式:dress1 dress2 shirt1 shirt2 swimsuit1 set1 set2... + +当前的多数独立站多款式是否参与搜索 +看起来搜索的索引粒度是spu单位的。 query加上sku相关信息,并不会让sku在spu内更靠前 + +下面的几个案例,都是我用 spu名称 + 其中一款的款式名称 进行搜索,看召回的spu 是否会将我指定的款式前置。 可以看到不管我是否加款式限定,返回结果的每个spu下的子sku顺序都不会受影响。 + + + + + +SPU-SKU索引建议方案 +spu为单位。SKU字段展开作为SPU属性 +其他重点字段 +1. Sku title +2. category +1. 数据源 +2. Mysql +在spu表中: +Field Type +category varchar(255) +category_id bigint(20) +category_google_id bigint(20) +category_level int(11) +category_path varchar(500) +3. ES索引 +1. 输入数据 + 设计 1,2,3级分类 三个字段,的 category (原始文本) +2. 索引方法 + 设计要求: +1. 支持facet(精确过滤、keyword聚合),并且性能需要足够高。 +2. 支持普通搜索模糊匹配(用户原始query可能包括分类词)。 +3. 模糊匹配要考虑多语言 +方案:采用方案2 +4. categoryPath索引 + Prefix 查询(categoryPath.keyword: "服装/男装")(如果满足条件的key太多的则性能较差,比如 查询的是一级类目,类目树叶子节点太多时性能较差) +5. categoryPath支撑模糊查询 和 多级cate keyword索引支撑精确查询。 索引阶段冗余,查询性能高。 + "category_path_zh": { // 提供模糊查询功能,辅助相关性计算 + "type": "text", + "analyzer": "hanlp_index", + "search_analyzer": "hanlp_standard" + }, + "category_path_en": { // 提供模糊查询功能,辅助相关性计算 + "type": "text", + "analyzer": "english", + "search_analyzer": "english" + }, + "category_path": { // 用于多层级的筛选、精确匹配 + "type": "keyword", + "normalizer": "lowercase" + }, + "category_id": { + "type": "keyword" + }, + "category_name": { + "type": "keyword" + }, + "category_level": { + "type": "integer" + }, + "category1_name": { // 不同层级下 可能有同名的情况,因此提供一二三级分开的查询方式 + "type": "keyword" + }, + "category2_name": { + "type": "keyword" + }, + "category3_name": { + "type": "keyword" + }, +3. tags + +1. 数据源 +多值 +标签 + +最多输入250个标签,每个不得超过500字符,多个标签请用「英文逗号」隔开 + +新品,热卖,爆款 + +耳机,头戴式,爆款 + +分割后 list形式灌入 +2. Mysql +3. ES索引 +1. 输入数据 +2. 索引方法 +4. 供应商 +1. 数据源 +2. Mysql +3. ES索引 +1. 输入数据 +2. 索引方法 +5. 款式/选项值(options) +1. 数据源 +以下区域字段,商品属性为M(商品主体)的行需填写款式名称,商品属性为P(子款式)的行需填写款式值信息,商品属性为S(单一款式商品)的行无需填写 + +款式1 +款式2 +款式3 + +最多255字符 +最多255字符 +最多255字符 + +SIZE +COLOR + + +S +red + + +S +black + + +S +army + + +L +red + + +L +black + + +L +army + + +XL +red + + +XL +black + + +XL +army + + +2. Mysql +1. API 在 SPU 的维度直接返回3个属性定义,存储在 shoplazza_product_option 中: +2. API在 SKU的维度直接返回3个属性值,存储在 shoplazza_product_sku 表的 option 相关的字段中: +3. ES索引 +1. 输入数据 +2. 索引方法 + 1)铺平展开,只支持三个,支持查询。缺点是,查询逻辑跟租户的属性维度绑定,不灵活 + attr1 + attr2 + attr3 + option1 + option2 + option3 + 2)nested,支持超过3个属性(动态)。支持查询 + "specifications": { + "type": "nested", + "properties": { + "name": { "type": "keyword" }, // "颜色", "容量" + "value": { "type": "keyword" } // "白色", "256GB" + } + }, + 3)nested,支持超过3个属性(动态)。只用作返回,不能查询。节省索引空间 + "specifications": { + "type": "nested", + "properties": { + "name": { "type": "keyword","index": false }, + "value": { "type": "keyword","index": false } + } + }, + + TODO 考虑使用方案(3)。 +6. SEO相关字段 +1. 数据源 +SEO标题 +SEO描述 +SEO URL Handle +SEO URL 重定向 +SEO关键词 + +最多5000字符 +最多5000字符 +最多支持输入255字符 + (SEO URL handle只对SEO URL的「URL参数」部分进行更改,即“products/”后的内容,如:products/「URL参数」 + ) +创建URL重定向,访问修改前链接可跳转到修改后的新链接页面 +「Y」:TRUE +「N」:FALSE +多个关键词请用「英文逗号」隔开 + + +2. Mysql +3. ES索引 +1. 输入数据 +2. 索引方法 +7. 供应商 +1. 数据源 +供应商名称 +供应商URL + +最多20字符 +请输入供应商URL + +Amazon +https://www.amazon.com/Legendary-Whitetails-Buck-Flannels-Large/dp/B01KTUMBOI/ref=sr_1_1?s=fashion-mens-intl-ship&ie=UTF8&qid=1543038722&sr=1-1 + +2. Mysql + +3. ES索引 +1. 输入数据 +2. 索引方法 +8. 其他 +1. 数据源 +2. Mysql +3. ES索引 +1. 输入数据 +2. 索引方法 +索引整体配置 +常用查询域(Query Domains) +1. default(默认索引): 搜索所有文本字段 + a. 包含字段:title, sku_titles(TODO), brief, description, seo_title(TODO待确认), seo_keywords, vendor, category_path, tags, category (带具体的语言后缀) +2. title(标题索引): 仅搜索标题相关字段 + a. 包含字段:title, sku_titles, seo_title (带具体的语言后缀) +3. vendor(品牌索引): 仅搜索品牌字段 + a. 包含字段:vendor (带具体的语言后缀) +4. category_path(类目索引): 仅搜索类目字段 + a. 包含字段:category_path(带具体的语言后缀) +5. tags(标签索引): 搜索标签和SEO关键词 + a. 包含字段:tags, seo_keywords +提权字段 +function_score +具体提权字段、权重待定(配置化) +"function_score": { + "functions": [ + { "field_value_factor": { "field": "sales_count", "factor": 0.001, "modifier": "log1p" } }, + { "gauss": { "listed_at": { "scale": "30d" } } } + ], + "boost_mode": "multiply" +}facet +分类 +tags + -- libgit2 0.21.2