Commit 4503d8bfb503652d7e57d83390c8789508ac1bc7
1 parent
3a33657d
更新文档《索引方案.md》
Showing
6 changed files
with
405 additions
and
38 deletions
Show diff stats
config/query_rewrite.dict
125 KB
27.3 KB
85.2 KB
| @@ -0,0 +1,388 @@ | @@ -0,0 +1,388 @@ | ||
| 1 | + | ||
| 2 | + | ||
| 3 | +公司文档地址:https://www.kdocs.cn/l/cav0b2rdk42n?from=docs&startTime=1763618428738&createDirect=true&newFile=true | ||
| 4 | +飞书地址:https://xp0y6kmku6.feishu.cn/wiki/ToYTwpjkViqPkZkcOz7cTZopnyc | ||
| 5 | + | ||
| 6 | +SPU-SKU索引方案选型 | ||
| 7 | +1. SKU为单位 + Collapse + inner_hits | ||
| 8 | +1. 优点: | ||
| 9 | +1. sku评分精准 (SKU 级别评分。如果sku影响相关性较多) | ||
| 10 | +2. 可扩展性:如果以后需要返回sku级别结果,索引改动小。 | ||
| 11 | +3. 索引更新灵活,单个sku字段变化只会引起单个sku的更新。 | ||
| 12 | +2. 缺点: | ||
| 13 | +1. inner_hits性能很差 | ||
| 14 | +2. spu级别的查询字段冗余,冗余倍数跟spu下面平均sku数量线性相关 | ||
| 15 | +3. 方案介绍 | ||
| 16 | +1. 查询性能: | ||
| 17 | + a. 主查询执行(召回结果)(比如5000sku) → collapse折叠(按spu_id分组、每组选top文档,比如得到1000sku) → 排序、按spu排序截取分页内结果(比如100) → 执行inner_hits (获取 spu内sku,相当于执行 page_size 次子查询) | ||
| 18 | + b. collapse阶段的耗时影响因素: | ||
| 19 | + i. 召回数量 、 基数(Cardinality)(去重后的spu数量,高基数字段collapse性能差)。 | ||
| 20 | + c. Inter hits(主要开销来源): | ||
| 21 | + i. 取决于分页size。(相当于page_size次子查询,"max_concurrent_group_searches"限制并发组查询) | ||
| 22 | + ii. 我们在宜采的实践,分页size=100的情况下,Inter hits开销非常大(Inter hits size = 4,只取id 不取任何sku字段、按原始打分排序) | ||
| 23 | + d. Inner hits 为什么性能差? | ||
| 24 | + i. 不对分桶内结果进行一次排序就行了吗?一个for循环的事情,为什么要用max_concurrent_group_searches线程去并发? | ||
| 25 | + ii. Collapse 阶段只保留每个分组的最佳文档,其他文档被丢弃。 | ||
| 26 | + iii. Collapse 阶段:每个分片独立执行collapse、最后协调节点做全局collapse。 | ||
| 27 | + iv. Inner_hits 阶段:每个spu下的sku可能在多个分片上,因此需要跨分片查询。 | ||
| 28 | + v. ES为什么要在collapse阶段丢弃其他文档: | ||
| 29 | + 1. 我的理解是,ES可能认为多数时候不需要inner_hits。Lazy Loading。对需要inner_hits的场景很不友好。 | ||
| 30 | + e. 即使collapse阶段只保留了最佳文档,为什么inner_hits阶段 为什么做page_size 100次查询、而不是做一次查询:spu_id in [1, 2, 3, ... 100个 ] AND (原始查询条件) 。 我们宜采的搜索就是这么做的。 | ||
| 31 | +阶段1:主查询 + Collapse | ||
| 32 | +├─ 每个分片执行查询 | ||
| 33 | +├─ 每个分片执行 collapse(只保留最高分文档) | ||
| 34 | +├─ 协调节点合并分片结果 | ||
| 35 | +└─ 输出:1000 个 SPU(每个只有 1 个 SKU) | ||
| 36 | + | ||
| 37 | +阶段2:Inner_hits(只对需要返回的分组执行) | ||
| 38 | +├─ 输入:100 个 SPU(size=100) | ||
| 39 | +├─ 对每个 SPU 执行查询: | ||
| 40 | +│ ├─ 构建查询:spu_id=123 AND (原始查询条件) | ||
| 41 | +│ ├─ 发送到所有分片 | ||
| 42 | +│ ├─ 等待分片响应 | ||
| 43 | +│ ├─ 合并分片结果 | ||
| 44 | +│ └─ 排序和截取(size=3) | ||
| 45 | +└─ 输出:100 个 SPU,每个有 3 个 SKU,按要求排序和填充2. 索引: | ||
| 46 | + a. 缺点:spu级别的查询字段冗余。比如1个spu下面有2*5个款式,那么 spu_title brielf description seo_keywords cate tags vendor 这些 spu 字段 将被重建10次索引。 | ||
| 47 | + b. 优点:索引更新灵活,单个sku字段变化只会引起单个sku的更新。 | ||
| 48 | +4. 参考资料 | ||
| 49 | +1. [Collapse search results](https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html) - collapse 在每个分片上独立执行,每个分片为每个折叠键选择代表文档,协调节点merge最佳文档 | ||
| 50 | +2. [Retrieve inner hits](https://www.elastic.co/guide/en/elasticsearch/reference/current/inner-hits.html) 每个折叠结果会触发额外的查询。 | ||
| 51 | +5. 适用场景: | ||
| 52 | +sku级别的字段对打分影响较大,搜索需要重点关注 sku级别的title、属性的匹配情况。 | ||
| 53 | +需要关注spu内部sku排序。 | ||
| 54 | +6. 跟我们的适配情况: | ||
| 55 | +1. 我们的 款式 多数情况并不影响搜索结果。 | ||
| 56 | + a. 相关性影响最重的 基本都在spu :spu_title brielf description seo_keywords cate tags vendor | ||
| 57 | + b. 款式:需要参与(甚至可以不参与)排序,但是对相关性影响很小 | ||
| 58 | +2. 款式 | ||
| 59 | + a. 笛卡尔积,variants多,冗余情况较严重 | ||
| 60 | +3. inner_hits的includes字段:我们可以只要ID,也就是只返回spu级别字段。 | ||
| 61 | + a. sku级别字段点击详情页再触发。 | ||
| 62 | + b. 如果需要sku级别字段,也可以将其作为spu的属性字段进行返回,而不用从inner_hits的includes获取。 | ||
| 63 | +4. 我们的 inner_hits 可能需要更多的source字段 | ||
| 64 | +2. SKU为单位 + Collapse 获得spu级别排序(不执行inner_hits) | ||
| 65 | +没有inner_hits的性能问题,但是仍然有 spu级别检索字段 冗余的问题。 | ||
| 66 | +3. spu为单位。SKU字段展开作为SPU属性 | ||
| 67 | +1. 索引方案 | ||
| 68 | +sku的title作为spu 的sku_titles 属性。 | ||
| 69 | +款式字段同样展开,作为 sku 的 list 属性。 | ||
| 70 | +除了title, brielf description seo相关 cate tags vendor所有影响相关性的字段都在spu。 sku只有一个title。所以,可以以spu为单位,sku的title作为spu的一个字段,以list形式灌入,假设一个spu有三个sku,那么这个sku_titles字段有三个值,打分的时候按max取得打分。 | ||
| 71 | +# 写入 spu 级别索引 | ||
| 72 | +def build_product_document(product, variants): | ||
| 73 | + return { | ||
| 74 | + "product_id": str(product.id), | ||
| 75 | + "title": product.title, | ||
| 76 | + | ||
| 77 | + # Variant搜索字段(展开) | ||
| 78 | + "variant_titles": [v.title for v in variants], | ||
| 79 | + "variant_attributes": self._extract_all_attributes(variants), | ||
| 80 | + | ||
| 81 | + # Variant详细信息(用于返回) | ||
| 82 | + "variants": [ | ||
| 83 | + { | ||
| 84 | + "id": str(v.id), | ||
| 85 | + "title": v.title, | ||
| 86 | + "price": float(v.price), | ||
| 87 | + "options": v.options | ||
| 88 | + } | ||
| 89 | + for v in variants | ||
| 90 | + ], | ||
| 91 | + | ||
| 92 | + # titles参与相关性计算 | ||
| 93 | + "titles": list(set([v.title for v in variants if v.title])), | ||
| 94 | + | ||
| 95 | + # 属性字段(扁平化,用于过滤) | ||
| 96 | + "option1": list(set([v.option1 for v in variants if v.option1])), | ||
| 97 | + "sizes": list(set([v.option2 for v in variants if v.option2])), | ||
| 98 | + | ||
| 99 | + "min_price": min(v.price for v in variants), | ||
| 100 | + "max_price": max(v.price for v in variants) | ||
| 101 | + }2. 查询方案 | ||
| 102 | +对数组字段使用 dis_max,只取最高分,避免累加。 | ||
| 103 | +3. 问题 | ||
| 104 | +不好得到每个子title的得分以决定sku的排序。方案: | ||
| 105 | +1. 打开explain,会影响性能,不推荐。(只需要记下来sku_titles 中每一项的打分,但是打开explain会记录太多的东西) | ||
| 106 | +2. 修改ES,把 sku_titles 数组中 每个title的匹配得分记下来。 | ||
| 107 | +3. 对返回的结果的子sku根据title和属性的匹配情况再做一次匹配,以决定sku的排序。 | ||
| 108 | +4. sku 作为nested | ||
| 109 | +如果需要查询nested字段,会需要nested join,本质是是父子文档的join。 | ||
| 110 | +性能影响因子:- 子文档数量:线性增长,每个SKU增加约 5-15ms 查询时间- 嵌套深度:指数增长,多级嵌套性能急剧下降- 查询复杂度:nested bool查询比普通查询慢 3-10倍 | ||
| 111 | +原因: | ||
| 112 | +1. 内部 Join 操作:ES 为每个 nested 对象创建隐藏文档,查询时需要 join | ||
| 113 | +2. 文档膨胀:1个SPU文档实际存储为 1+N 个文档(N=SKU数量) | ||
| 114 | +3. 内存开销:nested 查询需要加载所有匹配的父子文档到内存 | ||
| 115 | +适用场景: | ||
| 116 | +• 查询模式简单(主要是过滤,少用复杂评分) | ||
| 117 | +5. Spu sku 独立索引 | ||
| 118 | +spu-catalog-*:用于品牌、类目、商品介绍等宏观搜索。包括列表页搜索。 | ||
| 119 | +sku-catalog-*:用于具体规格搜索、下单。涉及到价格、库存筛选的查询。 | ||
| 120 | + | ||
| 121 | +两者各有各的字段: | ||
| 122 | +SPU索引: | ||
| 123 | +├─ 数据:品牌、类目、描述、SEO信息 | ||
| 124 | +├─ 更新频率:低(几天一次) | ||
| 125 | +├─ 查询场景:列表页、品牌搜索、类目浏览 | ||
| 126 | +└─ 优化方向:文本搜索、相关性排序 | ||
| 127 | + | ||
| 128 | +SKU索引: | ||
| 129 | +├─ 数据:规格、价格、库存 | ||
| 130 | +├─ 更新频率:高(实时更新) | ||
| 131 | +├─ 查询场景:详情页、规格筛选、价格排序 | ||
| 132 | +└─ 优化方向:精确匹配、数值范围查询 | ||
| 133 | +联合查询:使用 multi_search 或应用层合并 | ||
| 134 | + | ||
| 135 | +这种场景的效果 可以等同于 sku 作为nested方案,如果 sku 的nested字段,只有数值型的用于查询,其他的的只用于返回填充。 | ||
| 136 | + | ||
| 137 | +店匠商家SPU-SKU数据情况调研 | ||
| 138 | +商品(product)的多款式(variants)配置 | ||
| 139 | +3种属性/款式,是笛卡尔积的形式生成variants(sku) | ||
| 140 | +服装领域的多款式 | ||
| 141 | +服装领域,variants(sku)基本上都是 颜色、size。 | ||
| 142 | +size 基本上每个商品都有: | ||
| 143 | +XS S M L XL 3XL,有的还有4XL,5XL | ||
| 144 | +颜色: blue/orange/purple/green... | ||
| 145 | +款式:dress1 dress2 shirt1 shirt2 swimsuit1 set1 set2... | ||
| 146 | + | ||
| 147 | +当前的多数独立站多款式是否参与搜索 | ||
| 148 | +看起来搜索的索引粒度是spu单位的。 query加上sku相关信息,并不会让sku在spu内更靠前 | ||
| 149 | + | ||
| 150 | +下面的几个案例,都是我用 spu名称 + 其中一款的款式名称 进行搜索,看召回的spu 是否会将我指定的款式前置。 可以看到不管我是否加款式限定,返回结果的每个spu下的子sku顺序都不会受影响。 | ||
| 151 | + | ||
| 152 | + | ||
| 153 | + | ||
| 154 | + | ||
| 155 | + | ||
| 156 | +SPU-SKU索引建议方案 | ||
| 157 | +spu为单位。SKU字段展开作为SPU属性 | ||
| 158 | +其他重点字段 | ||
| 159 | +1. Sku title | ||
| 160 | +2. category | ||
| 161 | +1. 数据源 | ||
| 162 | +2. Mysql | ||
| 163 | +在spu表中: | ||
| 164 | +Field Type | ||
| 165 | +category varchar(255) | ||
| 166 | +category_id bigint(20) | ||
| 167 | +category_google_id bigint(20) | ||
| 168 | +category_level int(11) | ||
| 169 | +category_path varchar(500) | ||
| 170 | +3. ES索引 | ||
| 171 | +1. 输入数据 | ||
| 172 | + 设计 1,2,3级分类 三个字段,的 category (原始文本) | ||
| 173 | +2. 索引方法 | ||
| 174 | + 设计要求: | ||
| 175 | +1. 支持facet(精确过滤、keyword聚合),并且性能需要足够高。 | ||
| 176 | +2. 支持普通搜索模糊匹配(用户原始query可能包括分类词)。 | ||
| 177 | +3. 模糊匹配要考虑多语言 | ||
| 178 | +方案:采用方案2 | ||
| 179 | +4. categoryPath索引 + Prefix 查询(categoryPath.keyword: "服装/男装")(如果满足条件的key太多的则性能较差,比如 查询的是一级类目,类目树叶子节点太多时性能较差) | ||
| 180 | +5. categoryPath支撑模糊查询 和 多级cate keyword索引支撑精确查询。 索引阶段冗余,查询性能高。 | ||
| 181 | + "category_path_zh": { // 提供模糊查询功能,辅助相关性计算 | ||
| 182 | + "type": "text", | ||
| 183 | + "analyzer": "hanlp_index", | ||
| 184 | + "search_analyzer": "hanlp_standard" | ||
| 185 | + }, | ||
| 186 | + "category_path_en": { // 提供模糊查询功能,辅助相关性计算 | ||
| 187 | + "type": "text", | ||
| 188 | + "analyzer": "english", | ||
| 189 | + "search_analyzer": "english" | ||
| 190 | + }, | ||
| 191 | + "category_path": { // 用于多层级的筛选、精确匹配 | ||
| 192 | + "type": "keyword", | ||
| 193 | + "normalizer": "lowercase" | ||
| 194 | + }, | ||
| 195 | + "category_id": { | ||
| 196 | + "type": "keyword" | ||
| 197 | + }, | ||
| 198 | + "category_name": { | ||
| 199 | + "type": "keyword" | ||
| 200 | + }, | ||
| 201 | + "category_level": { | ||
| 202 | + "type": "integer" | ||
| 203 | + }, | ||
| 204 | + "category1_name": { // 不同层级下 可能有同名的情况,因此提供一二三级分开的查询方式 | ||
| 205 | + "type": "keyword" | ||
| 206 | + }, | ||
| 207 | + "category2_name": { | ||
| 208 | + "type": "keyword" | ||
| 209 | + }, | ||
| 210 | + "category3_name": { | ||
| 211 | + "type": "keyword" | ||
| 212 | + }, | ||
| 213 | +3. tags | ||
| 214 | + | ||
| 215 | +1. 数据源 | ||
| 216 | +多值 | ||
| 217 | +标签 | ||
| 218 | + | ||
| 219 | +最多输入250个标签,每个不得超过500字符,多个标签请用「英文逗号」隔开 | ||
| 220 | + | ||
| 221 | +新品,热卖,爆款 | ||
| 222 | + | ||
| 223 | +耳机,头戴式,爆款 | ||
| 224 | + | ||
| 225 | +分割后 list形式灌入 | ||
| 226 | +2. Mysql | ||
| 227 | +3. ES索引 | ||
| 228 | +1. 输入数据 | ||
| 229 | +2. 索引方法 | ||
| 230 | +4. 供应商 | ||
| 231 | +1. 数据源 | ||
| 232 | +2. Mysql | ||
| 233 | +3. ES索引 | ||
| 234 | +1. 输入数据 | ||
| 235 | +2. 索引方法 | ||
| 236 | +5. 款式/选项值(options) | ||
| 237 | +1. 数据源 | ||
| 238 | +以下区域字段,商品属性为M(商品主体)的行需填写款式名称,商品属性为P(子款式)的行需填写款式值信息,商品属性为S(单一款式商品)的行无需填写 | ||
| 239 | + | ||
| 240 | +款式1 | ||
| 241 | +款式2 | ||
| 242 | +款式3 | ||
| 243 | + | ||
| 244 | +最多255字符 | ||
| 245 | +最多255字符 | ||
| 246 | +最多255字符 | ||
| 247 | + | ||
| 248 | +SIZE | ||
| 249 | +COLOR | ||
| 250 | + | ||
| 251 | + | ||
| 252 | +S | ||
| 253 | +red | ||
| 254 | + | ||
| 255 | + | ||
| 256 | +S | ||
| 257 | +black | ||
| 258 | + | ||
| 259 | + | ||
| 260 | +S | ||
| 261 | +army | ||
| 262 | + | ||
| 263 | + | ||
| 264 | +L | ||
| 265 | +red | ||
| 266 | + | ||
| 267 | + | ||
| 268 | +L | ||
| 269 | +black | ||
| 270 | + | ||
| 271 | + | ||
| 272 | +L | ||
| 273 | +army | ||
| 274 | + | ||
| 275 | + | ||
| 276 | +XL | ||
| 277 | +red | ||
| 278 | + | ||
| 279 | + | ||
| 280 | +XL | ||
| 281 | +black | ||
| 282 | + | ||
| 283 | + | ||
| 284 | +XL | ||
| 285 | +army | ||
| 286 | + | ||
| 287 | + | ||
| 288 | +2. Mysql | ||
| 289 | +1. API 在 SPU 的维度直接返回3个属性定义,存储在 shoplazza_product_option 中: | ||
| 290 | +2. API在 SKU的维度直接返回3个属性值,存储在 shoplazza_product_sku 表的 option 相关的字段中: | ||
| 291 | +3. ES索引 | ||
| 292 | +1. 输入数据 | ||
| 293 | +2. 索引方法 | ||
| 294 | + 1)铺平展开,只支持三个,支持查询。缺点是,查询逻辑跟租户的属性维度绑定,不灵活 | ||
| 295 | + attr1 | ||
| 296 | + attr2 | ||
| 297 | + attr3 | ||
| 298 | + option1 | ||
| 299 | + option2 | ||
| 300 | + option3 | ||
| 301 | + 2)nested,支持超过3个属性(动态)。支持查询 | ||
| 302 | + "specifications": { | ||
| 303 | + "type": "nested", | ||
| 304 | + "properties": { | ||
| 305 | + "name": { "type": "keyword" }, // "颜色", "容量" | ||
| 306 | + "value": { "type": "keyword" } // "白色", "256GB" | ||
| 307 | + } | ||
| 308 | + }, | ||
| 309 | + 3)nested,支持超过3个属性(动态)。只用作返回,不能查询。节省索引空间 | ||
| 310 | + "specifications": { | ||
| 311 | + "type": "nested", | ||
| 312 | + "properties": { | ||
| 313 | + "name": { "type": "keyword","index": false }, | ||
| 314 | + "value": { "type": "keyword","index": false } | ||
| 315 | + } | ||
| 316 | + }, | ||
| 317 | + | ||
| 318 | + TODO 考虑使用方案(3)。 | ||
| 319 | +6. SEO相关字段 | ||
| 320 | +1. 数据源 | ||
| 321 | +SEO标题 | ||
| 322 | +SEO描述 | ||
| 323 | +SEO URL Handle | ||
| 324 | +SEO URL 重定向 | ||
| 325 | +SEO关键词 | ||
| 326 | + | ||
| 327 | +最多5000字符 | ||
| 328 | +最多5000字符 | ||
| 329 | +最多支持输入255字符 | ||
| 330 | + (SEO URL handle只对SEO URL的「URL参数」部分进行更改,即“products/”后的内容,如:products/「URL参数」 | ||
| 331 | + ) | ||
| 332 | +创建URL重定向,访问修改前链接可跳转到修改后的新链接页面 | ||
| 333 | +「Y」:TRUE | ||
| 334 | +「N」:FALSE | ||
| 335 | +多个关键词请用「英文逗号」隔开 | ||
| 336 | + | ||
| 337 | + | ||
| 338 | +2. Mysql | ||
| 339 | +3. ES索引 | ||
| 340 | +1. 输入数据 | ||
| 341 | +2. 索引方法 | ||
| 342 | +7. 供应商 | ||
| 343 | +1. 数据源 | ||
| 344 | +供应商名称 | ||
| 345 | +供应商URL | ||
| 346 | + | ||
| 347 | +最多20字符 | ||
| 348 | +请输入供应商URL | ||
| 349 | + | ||
| 350 | +Amazon | ||
| 351 | +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 | ||
| 352 | + | ||
| 353 | +2. Mysql | ||
| 354 | + | ||
| 355 | +3. ES索引 | ||
| 356 | +1. 输入数据 | ||
| 357 | +2. 索引方法 | ||
| 358 | +8. 其他 | ||
| 359 | +1. 数据源 | ||
| 360 | +2. Mysql | ||
| 361 | +3. ES索引 | ||
| 362 | +1. 输入数据 | ||
| 363 | +2. 索引方法 | ||
| 364 | +索引整体配置 | ||
| 365 | +常用查询域(Query Domains) | ||
| 366 | +1. default(默认索引): 搜索所有文本字段 | ||
| 367 | + a. 包含字段:title, sku_titles(TODO), brief, description, seo_title(TODO待确认), seo_keywords, vendor, category_path, tags, category (带具体的语言后缀) | ||
| 368 | +2. title(标题索引): 仅搜索标题相关字段 | ||
| 369 | + a. 包含字段:title, sku_titles, seo_title (带具体的语言后缀) | ||
| 370 | +3. vendor(品牌索引): 仅搜索品牌字段 | ||
| 371 | + a. 包含字段:vendor (带具体的语言后缀) | ||
| 372 | +4. category_path(类目索引): 仅搜索类目字段 | ||
| 373 | + a. 包含字段:category_path(带具体的语言后缀) | ||
| 374 | +5. tags(标签索引): 搜索标签和SEO关键词 | ||
| 375 | + a. 包含字段:tags, seo_keywords | ||
| 376 | +提权字段 | ||
| 377 | +function_score | ||
| 378 | +具体提权字段、权重待定(配置化) | ||
| 379 | +"function_score": { | ||
| 380 | + "functions": [ | ||
| 381 | + { "field_value_factor": { "field": "sales_count", "factor": 0.001, "modifier": "log1p" } }, | ||
| 382 | + { "gauss": { "listed_at": { "scale": "30d" } } } | ||
| 383 | + ], | ||
| 384 | + "boost_mode": "multiply" | ||
| 385 | +}facet | ||
| 386 | +分类 | ||
| 387 | +tags | ||
| 388 | + |
docs/索引字段说明.md
| @@ -171,28 +171,31 @@ category_path varchar(500) | @@ -171,28 +171,31 @@ category_path varchar(500) | ||
| 171 | ### 属性 | 171 | ### 属性 |
| 172 | 1. 组织ES输入数据的时候,需要为sku拼接spu的 option1 option2 option3,作为属性名称(比如“颜色”),sku的 option1 option2 option3 作为属性值(比如“白色”) | 172 | 1. 组织ES输入数据的时候,需要为sku拼接spu的 option1 option2 option3,作为属性名称(比如“颜色”),sku的 option1 option2 option3 作为属性值(比如“白色”) |
| 173 | 2. 有以下方案: TODO 可以选择其中一种,或者2用于填充3用于搜索: | 173 | 2. 有以下方案: TODO 可以选择其中一种,或者2用于填充3用于搜索: |
| 174 | -1)铺平展开,只支持三个 | 174 | +1)铺平展开,只支持三个,支持查询。缺点是,查询逻辑跟租户的属性维度绑定,不灵活 |
| 175 | attr1 | 175 | attr1 |
| 176 | attr2 | 176 | attr2 |
| 177 | attr3 | 177 | attr3 |
| 178 | option1 | 178 | option1 |
| 179 | option2 | 179 | option2 |
| 180 | option3 | 180 | option3 |
| 181 | -2)nested,支持多个,动态。 查询性能低 | 181 | +2)nested,支持超过3个属性(动态)。支持查询 |
| 182 | "specifications": { | 182 | "specifications": { |
| 183 | "type": "nested", | 183 | "type": "nested", |
| 184 | "properties": { | 184 | "properties": { |
| 185 | - "name": { "type": "keyword" }, // "颜色", "容量" | ||
| 186 | - "value": { "type": "keyword" } // "白色", "256GB" | 185 | + "name": { "type": "keyword" }, // "颜色", "容量" |
| 186 | + "value": { "type": "keyword" } // "白色", "256GB" | ||
| 187 | } | 187 | } |
| 188 | }, | 188 | }, |
| 189 | -3)平铺展开。写入时从 specifications 提取并填充这些字段,查询性能高。 | ||
| 190 | -"properties": { | ||
| 191 | - "color": { "type": "keyword" }, | ||
| 192 | - "capacity": { "type": "keyword" }, | ||
| 193 | - "network": { "type": "keyword" }, | ||
| 194 | - "edition": { "type": "keyword" } | ||
| 195 | -} | 189 | +3)nested,支持超过3个属性(动态)。只用作返回,不能查询。节省索引空间 |
| 190 | +"specifications": { | ||
| 191 | + "type": "nested", | ||
| 192 | + "properties": { | ||
| 193 | + "name": { "type": "keyword","index": false }, | ||
| 194 | + "value": { "type": "keyword","index": false } | ||
| 195 | + } | ||
| 196 | +}, | ||
| 197 | + | ||
| 198 | +考虑使用方案(3)。 | ||
| 196 | 199 | ||
| 197 | ### status | 200 | ### status |
| 198 | 1. 商品下架等状态 | 201 | 1. 商品下架等状态 |
| @@ -218,30 +221,7 @@ SEO关键词 | @@ -218,30 +221,7 @@ SEO关键词 | ||
| 218 | 221 | ||
| 219 | ## SPU 与 SKU 的协同设计 | 222 | ## SPU 与 SKU 的协同设计 |
| 220 | 223 | ||
| 221 | -以下方案: | ||
| 222 | -1. sku为索引单位。使用 collapse 按 spu_id 折叠 | ||
| 223 | -需要考虑大量的字段冗余 | ||
| 224 | - | ||
| 225 | -2. spu为单位。 sku的title作为 spu 的sku_titles 属性。 | ||
| 226 | - 除了title, brielf description seo相关 cate tags vendor所有影响相关性的字段都在spu。 sku只有一个title。所以,可以以spu为单位,sku的title作为spu的一个字段,以list形式灌入,假设一个spu有三个sku,那么这个sku_titles字段有三个值,打分的时候按max取得打分,并且我们可以得到这三个sku的title匹配的得分,因此好决定sku的排序。 | ||
| 227 | - | ||
| 228 | -3. sku 作为nested | ||
| 229 | - | ||
| 230 | - | ||
| 231 | - | ||
| 232 | -参考 [](https://blog.csdn.net/csdn_tom_168/article/details/150432666) | ||
| 233 | -方案一:独立索引 | ||
| 234 | -spu-catalog-*:用于品牌、类目、商品介绍等宏观搜索。 | ||
| 235 | -sku-catalog-*:用于具体规格搜索、下单。 | ||
| 236 | -优势:职责分离,查询更高效。 | ||
| 237 | - | ||
| 238 | -方案二:联合查询 | ||
| 239 | -GET /spu-read,sku-read/_search | ||
| 240 | -适用于“模糊搜索 → 跳转详情页”的场景。 | ||
| 241 | - | ||
| 242 | -方案三:父子文档(不推荐) | ||
| 243 | -join 类型维护 SPU-SKU 关系。 | ||
| 244 | -性能差,维护复杂,不适用于高并发搜索场景。 | 224 | +参考《索引spu-sku层级结构设计.md》 |
| 245 | 225 | ||
| 246 | 226 | ||
| 247 | ## rank - 相关性 | 227 | ## rank - 相关性 |