Commit 1c5366f5e46d0d8ed4bd7de0c9cbbfbb9fbbc884

Authored by tangwang
1 parent 9d0214bb

query分析性能优化

docs/issue-2026-03-29-索引修改-done-0330.md 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +
  2 +
  3 +
  4 +
  5 +
  6 +工程(金伟)配合修改:
  7 +
  8 +
  9 +一、tags字段改支持多语言:
  10 +spu表tags字段,跟title走一样的翻译逻辑,填入原始语言、zh、en。
  11 +
  12 +检查以下字段,都跟title一样走翻译逻辑
  13 +title
  14 +keywords
  15 +tags
  16 +brief
  17 +description
  18 +vendor
  19 +category_path
  20 +category_name_text
  21 +
  22 +
  23 +二、/indexer/enrich-content接口的修改
  24 +1. 请求参数,把language去掉,因为我返回的内容直接对应索引结构,不用你做处理了,因此不需要指定语言,降低耦合。
  25 +2. 返回 enriched_attributes enriched_tags qanchors三个字段,按原始内容填入。
  26 +3. enriched_tags是本次新增的,注意区别于tags字段。tags字段来源于mysql spu表,enriched_tags是本接口返回的。
  27 +
  28 +
  29 +三、specifications的value,需要翻译,也是需要填中英文:
  30 +{
  31 + "specifications": [
  32 + {
  33 + "sku_id": "sku-red-s",
  34 + "name": "color",
  35 + "value_keyword": "красный",
  36 + "value_text": {
  37 + "zh": "红色",
  38 + "en": "red"
  39 + }
  40 + }
  41 + ]
  42 +}
  43 +
... ...
docs/issue-2026-03-30-query分析性能优化-done-0331.md 0 → 100644
... ... @@ -0,0 +1,264 @@
  1 +
  2 +总体的目的是:
  3 +1)要对原始query进行翻译(通常是en/zh的一种或者两种)
  4 +2)对原始query要有关键词提取(关键词提取可能依赖分词;中英文分词要不一样,各自寻求最优性能的方法。zh的可以保持不变,en的可以优化)
  5 +3)其他的一些任务可能依赖分词
  6 +4)获取text embedding/clip embedding
  7 +
  8 +
  9 +英文关键词提取:走spacy进行关键词提取(即主干分析)。提取出query中的核心词,用于搜索时候的term求交,其余的词不参与求交、只用于权重计算。
  10 +
  11 +
  12 +实现:
  13 +
  14 +# Query 模块说明
  15 +
  16 +本目录实现搜索请求侧的**查询理解与解析**:在不做 Elasticsearch 语言计划拼装的前提下,产出可供检索层、重排层与调试界面消费的**结构化事实**(规范化文本、检测语言、可选翻译、文本与 CLIP 向量、分词与关键词、可选的样式意图与标题排除配置等)。下面按**当前实现**说明策略与数据流,便于与 `search/`、`context/`、`frontend/` 对照阅读。
  17 +
  18 +---
  19 +
  20 +## 包内文件与职责
  21 +
  22 +| 文件 | 作用 |
  23 +|------|------|
  24 +| `query_parser.py` | 入口 `QueryParser`:编排规范化、改写、语言检测、异步翻译与向量、分词、关键词、意图与排除检测;定义 `ParsedQuery`。 |
  25 +| `tokenization.py` | 轻量分词、文本规范化、`TokenizedText` 与按请求复用的 `QueryTextAnalysisCache`(模型分词与语言提示、粗细分词策略)。 |
  26 +| `keyword_extractor.py` | `KeywordExtractor`:中文走 HanLP 分词 + 词性名词串;英文走 spaCy 核心词;`collect_keywords_queries` 汇总 `base` 与各翻译语种。 |
  27 +| `english_keyword_extractor.py` | `EnglishKeywordExtractor`:`en_core_web_sm` + 依存/名词块规则,产出短字符串供检索侧关键词子句使用。 |
  28 +| `language_detector.py` | 脚本优先 + Lingua 的通用语言检测(与 `QueryParser` 的英文 ASCII 快路径配合使用)。 |
  29 +| `query_rewriter.py` | 基于配置词典的查询改写与规范化。 |
  30 +| `style_intent.py` | 从配置加载样式意图词表,对查询变体做候选匹配,产出 `StyleIntentProfile`。 |
  31 +| `product_title_exclusion.py` | 从配置加载标题排除规则,对多路查询文本做触发词匹配,产出 `ProductTitleExclusionProfile`。 |
  32 +
  33 +公开符号见 `query/__init__.py`(`QueryParser`、`ParsedQuery`、`KEYWORDS_QUERY_BASE_KEY` 等)。
  34 +
  35 +---
  36 +
  37 +## 解析产物:`ParsedQuery`
  38 +
  39 +`ParsedQuery` 是单次 `parse()` 的权威结果容器,字段含义与下游约定如下。
  40 +
  41 +- **`original_query` / `query_normalized` / `rewritten_query`**:分别为原始输入、规范化后、词典改写后的主查询文本;后续翻译、向量、默认分词与 `base` 关键词均以**改写后的 `rewritten_query`(在代码变量中常名为 `query_text`)**为基准。
  42 +- **`detected_language`**:解析时认定的源语言代码;若检测为 `unknown` 或空,则回退到 `SearchConfig.query_config.default_language`。
  43 +- **`translations`**:键为**目标语言代码**(如 `zh`、`en`),值为翻译服务返回的字符串;仅包含本次请求实际需要的目标语种(见下文翻译目标推导)。
  44 +- **`query_vector` / `image_query_vector`**:分别为 BGE 类文本向量与 CLIP 文本向量(维度由各自编码服务决定);未生成或未在超时内完成则为 `None`。
  45 +- **`query_tokens`**:对**改写后主查询**做分词后的字符串列表,供例如 KNN 参数按 token 数分支等逻辑使用;分词路径由 `QueryTextAnalysisCache` 决定(纯拉丁英文可走轻量分词,含汉字则走 HanLP)。
  46 +- **`keywords_queries`**:与「主查询 + 各翻译变体」平行的**关键词子查询**映射:键 `base`(常量 `KEYWORDS_QUERY_BASE_KEY`)对应源语言侧关键词串,其它键与 `translations` 的语种键一致。空串或无法提取的条目**不会写入**字典。
  47 +- **`style_intent_profile` / `product_title_exclusion_profile`**:可选的理解结果;是否生效完全由 `config.yaml` 中 `query_config` 的对应开关与词表/规则决定。
  48 +- **`_text_analysis_cache`**:单次解析内的分词与语言提示缓存,**不参与序列化**,仅供同一次 `parse` 内各检测器复用,避免对同一文本重复调用 HanLP。
  49 +
  50 +与重排相关的文本选择由独立函数 `rerank_query_text()` 完成:检测为 `zh` 或 `en` 时始终用原始查询;其它语言优先英译再中译,见 `query_parser.py` 中实现。
  51 +
  52 +---
  53 +
  54 +## `QueryParser.parse()` 的执行顺序与策略
  55 +
  56 +解析主流程在 `QueryParser.parse()` 中实现。整体目标是:在**共享等待预算**下并行完成翻译与向量请求,同时尽量减少主线程上重复、昂贵的分词与 NLP 调用,并把结果写入可选的 `context`(请求上下文)供日志与 `debug_info` 使用。
  57 +
  58 +### 1. 规范化与改写
  59 +
  60 +- 使用 `QueryNormalizer` 得到 `query_normalized` 并可选写入 `context.store_intermediate_result('query_normalized', ...)`。
  61 +- 若配置了改写词典,则用 `QueryRewriter` 可能更新 `query_text`;改写成功时记录 `rewritten_query` 与告警。
  62 +
  63 +### 2. 语言检测:通用路径与英文 ASCII 快路径
  64 +
  65 +- **快路径**:当「活跃语种集合」仅为 `en` 与 `zh` 的子集时(活跃集合取 `target_languages` 归一化结果,若为空则回退到 `query_config.supported_languages`),且当前查询为**纯 ASCII、含字母、不含汉字**,则**直接判定为 `en`**,不再调用 `LanguageDetector`(避免 Lingua 等开销)。逻辑见 `_detect_query_language()` 与 `_is_ascii_latin_query()`。
  66 +
  67 +```303:317:query/query_parser.py
  68 + def _detect_query_language(
  69 + self,
  70 + query_text: str,
  71 + *,
  72 + target_languages: Optional[List[str]] = None,
  73 + ) -> str:
  74 + normalized_targets = self._normalize_language_codes(target_languages)
  75 + supported_languages = self._normalize_language_codes(
  76 + getattr(self.config.query_config, "supported_languages", None)
  77 + )
  78 + active_languages = normalized_targets or supported_languages
  79 + if active_languages and set(active_languages).issubset({"en", "zh"}):
  80 + if self._is_ascii_latin_query(query_text):
  81 + return "en"
  82 + return self.language_detector.detect(query_text)
  83 +```
  84 +
  85 +- **通用路径**:`LanguageDetector` 先按 Unicode 脚本返回明确语种(如汉字块即 `zh`),否则用 Lingua 在一大组语言中判别,见 `language_detector.py`。
  86 +
  87 +检测最终结果写入 `context.store_intermediate_result('detected_language', ...)`(若提供 `context`)。
  88 +
  89 +### 3. 按请求分词缓存与语言提示
  90 +
  91 +每次 `parse` 会新建 `QueryTextAnalysisCache(tokenizer=self._tokenizer)`,并对**原始串、规范化串、改写后串**调用 `set_language_hint(..., detected_lang)`,使后续对同一文本的 `get_tokenizer_result` / `get_tokenized_text` 能按语言选择**是否调用 HanLP**。
  92 +
  93 +### 4. HanLP 模型(与 `KeywordExtractor` 对齐)
  94 +
  95 +`QueryParser` 默认构建的 `self._tokenizer` 为 HanLP 预训练分词模型 **`FINE_ELECTRA_SMALL_ZH`**,并开启 `output_spans=True`,以便与关键词提取共用「带偏移的分词结果」。
  96 +
  97 +```237:245:query/query_parser.py
  98 + def _build_tokenizer(self) -> Callable[[str], Any]:
  99 + """Build the tokenizer used by query parsing. No fallback path by design."""
  100 + if hanlp is None:
  101 + raise RuntimeError("HanLP is required for QueryParser tokenization")
  102 + logger.info("Initializing HanLP tokenizer...")
  103 + tokenizer = hanlp.load(hanlp.pretrained.tok.FINE_ELECTRA_SMALL_ZH)
  104 + tokenizer.config.output_spans = True
  105 + logger.info("HanLP tokenizer initialized")
  106 + return tokenizer
  107 +```
  108 +
  109 +`KeywordExtractor` 在未注入自定义 `tokenizer` 时同样加载 **`FINE_ELECTRA_SMALL_ZH`**,并额外加载 **`CTB9_POS_ELECTRA_SMALL`** 做词性标注;二者在「中文路径」上语义一致,便于复用 `tokenizer_result`。
  110 +
  111 +### 5. 异步富集:翻译、文本向量、CLIP 文本向量
  112 +
  113 +- 翻译目标:`translation_targets = normalized_targets` 中**去掉与检测源语言相同**的代码后的列表(例如源为 `en` 且索引语言为 `["en","zh"]` 时只翻 `zh`)。
  114 +- 翻译模型名:由 `_pick_query_translation_model()` 根据「源语言是否在索引语言内」及 `zh↔en` 等分支从 `QueryConfig` 选取。
  115 +- 当 `generate_vector` 为真且配置开启文本嵌入时,向线程池提交 `text_encoder.encode([query_text], ...)`;当配置了 `image_embedding_field` 时提交 `image_encoder.encode_clip_text(query_text, ...)`。
  116 +- 线程池:`ThreadPoolExecutor`,`max_workers` 为 `min(任务数, 4)` 与至少 1。
  117 +- **提交顺序**:先尽可能提交所有异步任务,再在主线程上做「与异步重叠」的轻量工作(见下一节),最后 `concurrent.futures.wait(..., timeout=budget_sec)`。超时未完成的任务会记 warning,并 `shutdown(wait=False)` 不阻塞关闭线程池。
  118 +
  119 +等待预算(毫秒)来自 `QueryConfig`:
  120 +
  121 +- 源语言在索引语言内:`translation_embedding_wait_budget_ms_source_in_index`
  122 +- 否则:`translation_embedding_wait_budget_ms_source_not_in_index`
  123 +
  124 +完成每个 future 后打 `Async enrichment task finished` 日志(含 `elapsed_ms`,为从提交到完成的大致墙钟时间)。
  125 +
  126 +### 6. 主查询分词与「base」关键词(与异步重叠)
  127 +
  128 +在异步任务已提交之后、`wait()` 之前,当前实现会:
  129 +
  130 +1. 通过 `text_analysis_cache.get_tokenizer_result(query_text)` 得到分词结果,再 `extract_token_strings` 得到 **`query_tokens`**;
  131 +2. 调用 `KeywordExtractor.extract_keywords(query_text, language_hint=detected_lang, tokenizer_result=...)` 得到 **`keywords_base_query`**(若失败则日志告警,base 关键词可能为空)。
  132 +
  133 +这样主线程在等翻译/向量时,已并行完成源侧分词与源侧关键词的大部分工作。
  134 +
  135 +### 7. 等待结束后的关键词汇总与检测器
  136 +
  137 +`wait()` 返回后:
  138 +
  139 +- 若有翻译结果,写入 `context.store_intermediate_result("translations", translations)`,并对每条翻译 `text_analysis_cache.set_language_hint(result, lang)`,保证后续对该翻译串的分词/关键词走正确语言路径。
  140 +- `collect_keywords_queries(...)` 合并 **`base`**(可传入已算好的 `base_keywords_query` 避免重复抽取)与各翻译语种的关键词,得到 **`keywords_queries`**;成功时 `context.store_intermediate_result("keywords_queries", keywords_queries)` 并打 `Keyword extraction completed` 日志。
  141 +- 构造带 `_text_analysis_cache` 的 `ParsedQuery` 草稿,依次调用 `StyleIntentDetector.detect` 与 `ProductTitleExclusionDetector.detect`,再把完整 `ParsedQuery` 返回。
  142 +
  143 +解析阶段会打聚合耗时日志 `Query parse stage timings`,字段含义为:
  144 +
  145 +- **`before_wait_ms`**:从解析开始计时点到进入 `wait()` 之前的主线程耗时(含规范化、改写、语言检测、提交异步任务、主查询分词、base 关键词等);
  146 +- **`async_wait_ms`**:`wait()` 阻塞时间;
  147 +- **`base_keywords_ms`**:base 关键词抽取耗时;
  148 +- **`keyword_tail_ms`**:`collect_keywords_queries` 及前后尾部逻辑中关键词相关部分的主要耗时;
  149 +- **`tail_sync_ms`**:`wait()` 之后整段同步尾巴(含关键词汇总、两检测器、写中间结果等)。
  150 +
  151 +---
  152 +
  153 +## 分词与 `QueryTextAnalysisCache`
  154 +
  155 +### `get_tokenizer_result`:何时走 HanLP,何时走轻量分词
  156 +
  157 +- 若未配置模型 `tokenizer`,直接返回空列表路径的轻量结果(由上层避免依赖)。
  158 +- 若根据**该文本的语言提示**与**是否含汉字**判断不需要模型:返回 `simple_tokenize_query` 的列表(字符串 token),**不调用 HanLP**。
  159 +- 否则对该文本调用一次 `self.tokenizer(text)`(HanLP),结果按文本缓存,同一次 `parse` 内重复访问同一字符串不会重复推理。
  160 +
  161 +核心判断在 `_should_use_model_tokenizer`:**语言提示为 `zh` 时,仅当文本含汉字才用模型**;非 `zh` 提示时,仅当文本含汉字才用模型。因此纯英文主查询在提示为 `en` 时走轻量分词;中文翻译串在 `set_language_hint(..., "zh")` 且含汉字时走 HanLP。
  162 +
  163 +### `coarse_tokens` 与 `fine_tokens`:`TokenizedText`
  164 +
  165 +- **`fine_tokens`**:来自 `extract_token_strings(get_tokenizer_result(...))`,在中文路径上即 HanLP 分词后的词串(已按规范化键去重保序)。
  166 +- **`coarse_tokens`**:由 `_build_coarse_tokens` 决定。若语言提示为 **`zh`**,或文本含汉字且已有 `tokenizer_tokens`,则 **粗粒度 token 与 fine 一致**(即采用模型分词粒度,而不用「整段 CJK 连成一项」的纯正则策略)。否则使用 `simple_tokenize_query`(适合拉丁词、数字、带连字符/撇号的英文词形)。
  167 +
  168 +```92:103:query/tokenization.py
  169 +def _build_coarse_tokens(
  170 + text: str,
  171 + *,
  172 + language_hint: Optional[str],
  173 + tokenizer_tokens: Sequence[str],
  174 +) -> List[str]:
  175 + normalized_language = normalize_query_text(language_hint)
  176 + if normalized_language == "zh" or (contains_han_text(text) and tokenizer_tokens):
  177 + # Chinese coarse tokenization should follow the model tokenizer rather than a
  178 + # regex that collapses the whole sentence into one CJK span.
  179 + return list(_dedupe_preserve_order(tokenizer_tokens))
  180 + return _dedupe_preserve_order(simple_tokenize_query(text))
  181 +```
  182 +
  183 +- **`candidates`**:在 fine、coarse、两类 n-gram 短语(上限由 `max_ngram` 控制)以及整句 `normalized_text` 上合并去重,供 `StyleIntentDetector`、`ProductTitleExclusionDetector` 等做子串/短语级匹配。
  184 +
  185 +`tokenize_text()` 是对单次无缓存场景的薄封装:内部新建 `QueryTextAnalysisCache` 再 `get_tokenized_text`。
  186 +
  187 +---
  188 +
  189 +## 关键词提取:`KeywordExtractor` 与 `collect_keywords_queries`
  190 +
  191 +### 路由规则
  192 +
  193 +`extract_keywords` 根据 `language_hint` 分支:
  194 +
  195 +- **`en`**:完全交给 `EnglishKeywordExtractor`(spaCy),**不使用** HanLP 分词结果做 POS 名词筛选(即使调用方传入 `tokenizer_result` 也会被忽略在该路径内)。
  196 +- **`zh`**:使用 HanLP 分词结果(优先复用传入的 `tokenizer_result`),再对词序列跑 `CTB9_POS_ELECTRA_SMALL`,保留**长度 ≥ 2 且词性以 `N` 开头**的词;非连续名词之间插入空格拼接成一条字符串(与 ES 侧 `keywords_query` 的用法一致)。
  197 +- **其它非空语言码**:当前实现返回空串,即**不为该语种生成关键词子句**(由调用方决定是否跳过)。
  198 +
  199 +### `collect_keywords_queries`
  200 +
  201 +- 键 **`base`**:对应 `rewritten_query` 的关键词;若调用方已预先计算 `base_keywords_query` 则直接写入,避免重复抽取。
  202 +- 其它键:与 `translations` 中每个非空语种一一对应,语言码归一化为小写。
  203 +- 全程可传入 `text_analysis_cache`,以便 `get_tokenizer_result` 命中缓存并与检测器共享分词结果。
  204 +
  205 +常量 `KEYWORDS_QUERY_BASE_KEY` 的值为字符串 **`"base"`**,与检索构建里读取的字段一致。
  206 +
  207 +---
  208 +
  209 +## 英文关键词:`EnglishKeywordExtractor`
  210 +
  211 +- 依赖 **spaCy** 模型 **`en_core_web_sm`**,加载时关闭 `ner`、`textcat` 以减轻开销;加载失败时记录 warning 并走基于 `simple_tokenize_query` 的回退策略。
  212 +- 主路径用依存句法与名词块规则收集一小组「核心词」候选(如直接宾语名词、部分 ROOT 名词/专有名词、INTJ 结构下的宾语等),并处理价格/目的介词宾语降级、人口学名词(如 `women`)弱化、尺寸类 ROOT 与主语搭配等边界情况。
  213 +- 使用 `_project_terms_to_query_tokens` 将 spaCy 词形映射回查询中的**表面分词**(例如复合词 `t-shirt`),避免在关键词串中出现被错误切断的片段。
  214 +
  215 +最终返回**最多三个词**的空格连接字符串,用于检索侧第二层 `combined_fields` 的紧凑查询(见下节)。
  216 +
  217 +---
  218 +
  219 +## 与检索层的关系(消费方摘要)
  220 +
  221 +`ParsedQuery.keywords_queries` 由 `search/es_query_builder.py` 读取:在构建某一语言的 lexical 子句时,除主 `combined_fields`(完整 `query`)外,若存在非空的 `keywords_query` 且与主查询不同,会追加第二个 `combined_fields`,使用单独的 `minimum_should_match`(由 builder 的 `keywords_minimum_should_match` 配置)和较低 boost,从而在**不替代全文查询**的前提下加强核心词匹配。
  222 +
  223 +`query_tokens` 在同文件中间接影响例如带文本向量时的 KNN 分支参数(按 token 数量选用长查询的 k / num_candidates 等)。具体字段与 boost 以 `ESQueryBuilder` 当前实现为准。
  224 +
  225 +---
  226 +
  227 +## 样式意图与标题排除(简要)
  228 +
  229 +- **`StyleIntentRegistry` / `StyleIntentDetector`**:从 `QueryConfig.style_intent_terms` 等加载意图定义;`detect` 时按中英变体取查询文本,经 `tokenize_text` 或缓存得到 `TokenizedText`,在 `candidates` 上与配置同义词表匹配,输出 `StyleIntentProfile`(含 `query_variants` 与命中意图列表)。
  230 +- **`ProductTitleExclusionRegistry` / `ProductTitleExclusionDetector`**:从 `QueryConfig.product_title_exclusion_rules` 加载规则;对 `original_query`、`query_normalized`、`rewritten_query` 及所有 `translations` 去重后分词匹配触发词,输出 `ProductTitleExclusionProfile`。
  231 +
  232 +二者均依赖 `tokenization` 与可选的 HanLP,启用与否由配置项控制。
  233 +
  234 +---
  235 +
  236 +## 可观测性与调试
  237 +
  238 +当 `QueryParser.parse(..., context=...)` 传入请求上下文时,典型中间结果包括:
  239 +
  240 +- `query_normalized`、`rewritten_query`、`detected_language`、`query_tokens`
  241 +- `translation_{lang}`、`translations`
  242 +- `keywords_queries`
  243 +- `query_vector_shape`、`image_query_vector_shape`
  244 +- `style_intent_profile`、`product_title_exclusion_profile`
  245 +
  246 +搜索主流程在 `search/searcher.py` 中会把解析结果写入 `QueryAnalysisResult`(含 **`keywords_queries`**),并在 `debug=true` 时把 `query_analysis` 挂到响应的 `debug_info`;前端调试页在 `frontend/static/js/app.js` 中展示 **Translations** 与 **Keywords Queries** 等块,便于与翻译结果并列查看。
  247 +
  248 +---
  249 +
  250 +## 依赖与环境提示
  251 +
  252 +- **HanLP**:分词与中文词性标注;模型名以本文与源码为准(`FINE_ELECTRA_SMALL_ZH` + `CTB9_POS_ELECTRA_SMALL`)。
  253 +- **spaCy**:英文关键词路径需要可导入的 **`en_core_web_sm`**(若缺失则英文关键词退化为轻量规则)。
  254 +- **Lingua**:通用语言检测(在英文 ASCII 快路径不适用时参与拉丁语系判别)。
  255 +
  256 +运行与测试时请使用项目约定的虚拟环境(见仓库根目录 `CLAUDE.md` / `activate.sh`),避免系统 Python 缺少上述依赖。
  257 +
  258 +---
  259 +
  260 +## 扩展与测试
  261 +
  262 +- 单元测试中与解析、分词、意图相关的用例分布在 `tests/test_query_parser_mixed_language.py`、`tests/test_tokenization.py`、`tests/test_style_intent.py`、`tests/test_product_title_exclusion.py` 等文件中;修改分词或关键词策略时应同步更新或新增测试,以保持与本文描述一致。
  263 +
  264 +若新增语种或改写语言检测策略,应同步审视:`QueryParser._detect_query_language`、`QueryTextAnalysisCache._should_use_model_tokenizer`、`KeywordExtractor.extract_keywords` 中非 `zh`/`en` 分支,以及 ES 侧是否应为新语种生成 `keywords_query`。
... ...
docs/搜索API对接指南-01-搜索接口.md
... ... @@ -24,6 +24,76 @@ headers = {
24 24 response = requests.post(url, headers=headers, json={"query": "芭比娃娃"})
25 25 ```
26 26  
  27 +**cURL 示例(复制即可试)**
  28 +
  29 +将 `BASE_URL`、`TENANT_ID` 换成你的环境与租户。本地开发默认后端为 `http://localhost:6002`(见 `scripts/start_backend.sh`)。
  30 +
  31 +```bash
  32 +export BASE_URL="${BASE_URL:-http://localhost:6002}"
  33 +export TENANT_ID="${TENANT_ID:-162}" # 改成真实租户
  34 +```
  35 +
  36 +**1)基础检索**:关键词、分页、`language` 控制返回字段语言。
  37 +
  38 +```bash
  39 +curl -sS "$BASE_URL/search/" \
  40 + -H "Content-Type: application/json" \
  41 + -H "X-Tenant-ID: $TENANT_ID" \
  42 + -d '{
  43 + "query": "芭比娃娃",
  44 + "size": 20,
  45 + "from": 0,
  46 + "language": "zh"
  47 + }'
  48 +```
  49 +
  50 +**2)过滤 + 价格区间 + 分面 + 排序**:联调最常见组合(品牌 OR、`min_price` 区间、类目与颜色分面、按最低价升序)。
  51 +
  52 +```bash
  53 +curl -sS "$BASE_URL/search/" \
  54 + -H "Content-Type: application/json" \
  55 + -H "X-Tenant-ID: $TENANT_ID" \
  56 + -d '{
  57 + "query": "手机",
  58 + "size": 20,
  59 + "from": 0,
  60 + "language": "zh",
  61 + "filters": {
  62 + "vendor.zh.keyword": ["品牌A", "品牌B"]
  63 + },
  64 + "range_filters": {
  65 + "min_price": {"gte": 50, "lte": 200}
  66 + },
  67 + "facets": [
  68 + {"field": "category1_name", "size": 15, "type": "terms"},
  69 + {"field": "specifications.color", "size": 20, "type": "terms"}
  70 + ],
  71 + "sort_by": "min_price",
  72 + "sort_order": "asc"
  73 + }'
  74 +```
  75 +
  76 +**3)规格过滤 + SKU 维度 + 调试**:`specifications` 嵌套过滤、`sku_filter_dimension` 每组只保留一个 SKU;`debug: true` 便于对照 ES 与解析结果。
  77 +
  78 +```bash
  79 +curl -sS "$BASE_URL/search/" \
  80 + -H "Content-Type: application/json" \
  81 + -H "X-Tenant-ID: $TENANT_ID" \
  82 + -d '{
  83 + "query": "手机",
  84 + "size": 10,
  85 + "from": 0,
  86 + "language": "zh",
  87 + "filters": {
  88 + "specifications": {"name": "color", "value": "white"}
  89 + },
  90 + "sku_filter_dimension": ["color"],
  91 + "debug": true
  92 + }'
  93 +```
  94 +
  95 +需要美化 JSON 输出时,在命令末尾追加 ` | jq .`(需本机安装 [jq](https://jqlang.github.io/jq/))。
  96 +
27 97 ### 3.2 请求参数
28 98  
29 99 #### 完整请求体结构
... ... @@ -897,5 +967,19 @@ response = requests.post(url, headers=headers, json={"query": "芭比娃娃"})
897 967 }
898 968 ```
899 969  
  970 +**cURL(第 2 页,每页 20 条)**:
  971 +
  972 +```bash
  973 +curl -sS "${BASE_URL:-http://localhost:6002}/search/" \
  974 + -H "Content-Type: application/json" \
  975 + -H "X-Tenant-ID: ${TENANT_ID:-162}" \
  976 + -d '{
  977 + "query": "手机",
  978 + "size": 20,
  979 + "from": 20,
  980 + "language": "zh"
  981 + }'
  982 +```
  983 +
900 984 ---
901 985  
... ...
docs/搜索API对接指南-速查表.md
1 1 # API 快速参考 (v3.0)
2 2  
  3 +## 环境与 cURL
  4 +
  5 +- **默认地址**:`http://localhost:6002`(与仓库 `scripts/start_backend.sh` 一致)。
  6 +- **租户**:必须使用请求头 **`X-Tenant-ID`**(推荐);一般不要依赖把 `tenant_id` 放在 URL 上。
  7 +- 下列命令假设已设置:
  8 +
  9 +```bash
  10 +export BASE_URL="${BASE_URL:-http://localhost:6002}"
  11 +export TENANT_ID="${TENANT_ID:-163}" # 改成你的租户ID
  12 +```
  13 +
3 14 ## 基础搜索
4 15  
5 16 ```bash
6   -POST /search/
7   -{
8   - "query": "芭比娃娃",
9   - "size": 20
10   -}
  17 +curl -sS "$BASE_URL/search/" \
  18 + -H "Content-Type: application/json" \
  19 + -H "X-Tenant-ID: $TENANT_ID" \
  20 + -d '{
  21 + "query": "芭比娃娃",
  22 + "size": 20,
  23 + "from": 0,
  24 + "language": "zh"
  25 + }'
11 26 ```
12 27  
  28 +等同请求:`POST /search/`,请求体含 `query`、`size`、`from`、`language`。
  29 +
13 30 ---
14 31  
15 32 ## 精确匹配过滤
16 33  
  34 +在 `POST /search/` 的 JSON 里使用 `filters`(下面示例与「完整示例」可对照字段含义):
  35 +
17 36 ```bash
18   -{
19   - "filters": {
20   - "category_name": "手机", // 单值
21   - "category1_name": "服装", // 一级类目
22   - "vendor.zh.keyword": ["奇乐", "品牌A"], // 多值(OR)
23   - "tags": "手机", // 标签
24   - // specifications 嵌套过滤
25   - "specifications": {
26   - "name": "color",
27   - "value": "white"
  37 +curl -sS "$BASE_URL/search/" \
  38 + -H "Content-Type: application/json" \
  39 + -H "X-Tenant-ID: $TENANT_ID" \
  40 + -d '{
  41 + "query": "手机",
  42 + "size": 10,
  43 + "language": "zh",
  44 + "filters": {
  45 + "category_name": "手机",
  46 + "category1_name": "服装",
  47 + "vendor.zh.keyword": ["奇乐", "品牌A"],
  48 + "tags": "手机",
  49 + "specifications": {"name": "color", "value": "white"}
28 50 }
29   - }
30   -}
  51 + }'
31 52 ```
32 53  
33 54 ### Specifications 过滤
34 55  
35   -**单个规格**:
  56 +**单个规格**:
  57 +
36 58 ```bash
37   -{
38   - "filters": {
39   - "specifications": {"name": "color", "value": "white"}
40   - }
41   -}
  59 +curl -sS "$BASE_URL/search/" \
  60 + -H "Content-Type: application/json" \
  61 + -H "X-Tenant-ID: $TENANT_ID" \
  62 + -d '{
  63 + "query": "手机",
  64 + "size": 10,
  65 + "language": "zh",
  66 + "filters": {
  67 + "specifications": {"name": "color", "value": "white"}
  68 + }
  69 + }'
42 70 ```
43 71  
44   -**多个规格(按维度分组)**:
  72 +**多个规格(不同 name 为 AND)**:
  73 +
45 74 ```bash
46   -{
47   - "filters": {
48   - "specifications": [
49   - {"name": "color", "value": "white"},
50   - {"name": "size", "value": "256GB"}
51   - ]
52   - }
53   -}
  75 +curl -sS "$BASE_URL/search/" \
  76 + -H "Content-Type: application/json" \
  77 + -H "X-Tenant-ID: $TENANT_ID" \
  78 + -d '{
  79 + "query": "手机",
  80 + "size": 10,
  81 + "language": "zh",
  82 + "filters": {
  83 + "specifications": [
  84 + {"name": "color", "value": "white"},
  85 + {"name": "size", "value": "256GB"}
  86 + ]
  87 + }
  88 + }'
54 89 ```
55 90 说明:不同维度(不同name)是AND关系,相同维度(相同name)的多个值是OR关系。
56 91  
... ... @@ -59,14 +94,17 @@ POST /search/
59 94 ## 范围过滤
60 95  
61 96 ```bash
62   -{
63   - "range_filters": {
64   - "min_price": {
65   - "gte": 50, // >=
66   - "lte": 200 // <=
  97 +curl -sS "$BASE_URL/search/" \
  98 + -H "Content-Type: application/json" \
  99 + -H "X-Tenant-ID: $TENANT_ID" \
  100 + -d '{
  101 + "query": "玩具",
  102 + "size": 20,
  103 + "language": "zh",
  104 + "range_filters": {
  105 + "min_price": {"gte": 50, "lte": 200}
67 106 }
68   - }
69   -}
  107 + }'
70 108 ```
71 109  
72 110 **操作符**: `gte` (>=), `gt` (>), `lte` (<=), `lt` (<)
... ... @@ -78,47 +116,73 @@ POST /search/
78 116 ### 简单模式
79 117  
80 118 ```bash
81   -{
82   - "facets": ["category1_name", "category2_name", "category3_name", "specifications"]
83   -}
  119 +curl -sS "$BASE_URL/search/" \
  120 + -H "Content-Type: application/json" \
  121 + -H "X-Tenant-ID: $TENANT_ID" \
  122 + -d '{
  123 + "query": "玩具",
  124 + "size": 20,
  125 + "language": "zh",
  126 + "facets": ["category1_name", "category2_name", "category3_name", "specifications"]
  127 + }'
84 128 ```
85 129  
86 130 ### Specifications 分面
87 131  
88   -**所有规格名称**:
  132 +**所有规格名称**:
  133 +
89 134 ```bash
90   -{
91   - "facets": ["specifications"] // 返回所有name及其value列表
92   -}
  135 +curl -sS "$BASE_URL/search/" \
  136 + -H "Content-Type: application/json" \
  137 + -H "X-Tenant-ID: $TENANT_ID" \
  138 + -d '{
  139 + "query": "手机",
  140 + "size": 10,
  141 + "language": "zh",
  142 + "facets": ["specifications"]
  143 + }'
93 144 ```
94 145  
95   -**指定规格名称**:
  146 +**指定规格名称**:
  147 +
96 148 ```bash
97   -{
98   - "facets": ["specifications.color", "specifications.size", "specifications.material"] // 只返回指定name的value列表
99   -}
  149 +curl -sS "$BASE_URL/search/" \
  150 + -H "Content-Type: application/json" \
  151 + -H "X-Tenant-ID: $TENANT_ID" \
  152 + -d '{
  153 + "query": "手机",
  154 + "size": 10,
  155 + "language": "zh",
  156 + "facets": ["specifications.color", "specifications.size", "specifications.material"]
  157 + }'
100 158 ```
101 159  
102 160 ### 高级模式
103 161  
104 162 ```bash
105   -{
106   - "facets": [
107   - {"field": "category1_name", "size": 15},
108   - {
109   - "field": "min_price",
110   - "type": "range",
111   - "ranges": [
112   - {"key": "0-50", "to": 50},
113   - {"key": "50-100", "from": 50, "to": 100}
114   - ]
115   - },
116   - "specifications", // 所有规格名称
117   - "specifications.color", // 指定规格名称
118   - "specifications.size",
119   - "specifications.material"
120   - ]
121   -}
  163 +curl -sS "$BASE_URL/search/" \
  164 + -H "Content-Type: application/json" \
  165 + -H "X-Tenant-ID: $TENANT_ID" \
  166 + -d '{
  167 + "query": "手机",
  168 + "size": 20,
  169 + "language": "zh",
  170 + "facets": [
  171 + {"field": "category1_name", "size": 15},
  172 + {
  173 + "field": "min_price",
  174 + "type": "range",
  175 + "ranges": [
  176 + {"key": "0-50", "to": 50},
  177 + {"key": "50-100", "from": 50, "to": 100}
  178 + ]
  179 + },
  180 + "specifications",
  181 + "specifications.color",
  182 + "specifications.size",
  183 + "specifications.material"
  184 + ]
  185 + }'
122 186 ```
123 187  
124 188 ---
... ... @@ -128,12 +192,19 @@ POST /search/
128 192 **功能**: 按指定维度对每个SPU下的SKU进行分组,每组只返回第一个SKU。
129 193  
130 194 ```bash
131   -{
132   - "query": "芭比娃娃",
133   - "sku_filter_dimension": "color" // 按颜色筛选(假设option1_name="color")
134   -}
  195 +curl -sS "$BASE_URL/search/" \
  196 + -H "Content-Type: application/json" \
  197 + -H "X-Tenant-ID: $TENANT_ID" \
  198 + -d '{
  199 + "query": "芭比娃娃",
  200 + "size": 20,
  201 + "language": "zh",
  202 + "sku_filter_dimension": ["color"]
  203 + }'
135 204 ```
136 205  
  206 +(`sku_filter_dimension` 为数组;按颜色筛选时需索引里 `option*_name` 与维度一致,见正文说明。)
  207 +
137 208 **支持的维度值**:
138 209 - `option1`, `option2`, `option3`: 直接使用选项字段
139 210 - 规格名称(如 `color`, `size`): 通过 `option1_name`、`option2_name`、`option3_name` 匹配
... ... @@ -157,10 +228,16 @@ POST /search/
157 228 ## 排序
158 229  
159 230 ```bash
160   -{
161   - "sort_by": "min_price",
162   - "sort_order": "asc" // asc 或 desc
163   -}
  231 +curl -sS "$BASE_URL/search/" \
  232 + -H "Content-Type: application/json" \
  233 + -H "X-Tenant-ID: $TENANT_ID" \
  234 + -d '{
  235 + "query": "玩具",
  236 + "size": 20,
  237 + "language": "zh",
  238 + "sort_by": "min_price",
  239 + "sort_order": "asc"
  240 + }'
164 241 ```
165 242  
166 243 ---
... ... @@ -168,46 +245,57 @@ POST /search/
168 245 ## 分页
169 246  
170 247 ```bash
171   -{
172   - "size": 20, // 每页数量
173   - "from": 0 // 偏移量(第1页=0,第2页=20)
174   -}
  248 +curl -sS "$BASE_URL/search/" \
  249 + -H "Content-Type: application/json" \
  250 + -H "X-Tenant-ID: $TENANT_ID" \
  251 + -d '{
  252 + "query": "手机",
  253 + "size": 20,
  254 + "from": 20,
  255 + "language": "zh"
  256 + }'
175 257 ```
176 258  
  259 +(第 1 页 `from: 0`,第 2 页 `from: 20`,以此类推。)
  260 +
177 261 ---
178 262  
179 263 ## 完整示例
180 264  
  265 +一键联调:过滤 + 区间 + 分面 + 排序 + SKU 维度(请按实际类目/规格改 `filters`)。
  266 +
181 267 ```bash
182   -POST /search/
183   -Headers: X-Tenant-ID: 162
184   -{
185   - "query": "手机",
186   - "size": 20,
187   - "from": 0,
188   - "language": "zh",
189   - "filters": {
190   - "category_name": "手机",
191   - "category1_name": "电子产品",
192   - "specifications": {"name": "color", "value": "white"}
193   - },
194   - "range_filters": {
195   - "min_price": {"gte": 50, "lte": 200}
196   - },
197   - "facets": [
198   - {"field": "category1_name", "size": 15},
199   - {"field": "category2_name", "size": 15},
200   - "specifications.color",
201   - "specifications.size"
202   - ],
203   - "sort_by": "min_price",
204   - "sort_order": "asc",
205   - "sku_filter_dimension": "color" // 可选:按颜色筛选SKU
206   -}
  268 +curl -sS "$BASE_URL/search/" \
  269 + -H "Content-Type: application/json" \
  270 + -H "X-Tenant-ID: $TENANT_ID" \
  271 + -d '{
  272 + "query": "手机",
  273 + "size": 20,
  274 + "from": 0,
  275 + "language": "zh",
  276 + "filters": {
  277 + "category_name": "手机",
  278 + "category1_name": "电子产品",
  279 + "specifications": {"name": "color", "value": "white"}
  280 + },
  281 + "range_filters": {
  282 + "min_price": {"gte": 50, "lte": 200}
  283 + },
  284 + "facets": [
  285 + {"field": "category1_name", "size": 15},
  286 + {"field": "category2_name", "size": 15},
  287 + "specifications.color",
  288 + "specifications.size"
  289 + ],
  290 + "sort_by": "min_price",
  291 + "sort_order": "asc",
  292 + "sku_filter_dimension": ["color"]
  293 + }'
207 294 ```
208 295  
209 296 ---
210 297  
  298 +
211 299 ## 响应格式
212 300  
213 301 ```json
... ... @@ -275,26 +363,60 @@ Headers: X-Tenant-ID: 162
275 363  
276 364 ## 其他端点
277 365  
  366 +**图搜**(`POST /search/image`,与文本搜一样带 `X-Tenant-ID`):
  367 +
278 368 ```bash
279   -POST /search/image
280   -{
281   - "image_url": "https://example.com/image.jpg",
282   - "size": 20
283   -}
  369 +curl -sS "$BASE_URL/search/image" \
  370 + -H "Content-Type: application/json" \
  371 + -H "X-Tenant-ID: $TENANT_ID" \
  372 + -d '{
  373 + "image_url": "https://example.com/product.jpg",
  374 + "size": 20,
  375 + "range_filters": {
  376 + "min_price": {"gte": 10, "lte": 500}
  377 + }
  378 + }'
  379 +```
  380 +
  381 +(图搜请求体仅支持 `image_url`、`size`、可选的 `filters` / `range_filters`;与文本搜的 `language` / `from` 无关。)
  382 +
  383 +**搜索建议**:
  384 +
  385 +```bash
  386 +curl -sS -G "$BASE_URL/search/suggestions" \
  387 + --data-urlencode "q=芭" \
  388 + --data-urlencode "size=5" \
  389 + --data-urlencode "language=zh" \
  390 + -H "X-Tenant-ID: $TENANT_ID"
  391 +```
284 392  
285   -GET /search/suggestions?q=芭&size=5&language=zh
  393 +**即时搜索**(当前实现返回 501,勿用于生产):
286 394  
287   -GET /search/instant?q=玩具&size=5 # 当前返回 501 Not Implemented
  395 +```bash
  396 +curl -sS -G "$BASE_URL/search/instant" \
  397 + --data-urlencode "q=玩具" \
  398 + --data-urlencode "size=5" \
  399 + -H "X-Tenant-ID: $TENANT_ID"
  400 +```
288 401  
289   -GET /search/{doc_id}
  402 +**按文档 ID 取详情**(将 `YOUR_SPU_ID` 换成真实 `spu_id`):
290 403  
291   -GET /admin/health
292   -GET /admin/config
293   -GET /admin/stats # 需 X-Tenant-ID 或 tenant_id
  404 +```bash
  405 +curl -sS "$BASE_URL/search/YOUR_SPU_ID" \
  406 + -H "X-Tenant-ID: $TENANT_ID"
  407 +```
  408 +
  409 +**运维**:
  410 +
  411 +```bash
  412 +curl -sS "$BASE_URL/admin/health"
  413 +curl -sS "$BASE_URL/admin/config"
  414 +curl -sS "$BASE_URL/admin/stats" -H "X-Tenant-ID: $TENANT_ID"
294 415 ```
295 416  
296 417 ---
297 418  
  419 +
298 420 ## Python 快速示例
299 421  
300 422 ```python
... ...
query/README.md 0 → 100644
... ... @@ -0,0 +1,251 @@
  1 +# Query 模块说明
  2 +
  3 +本目录实现搜索请求侧的**查询理解与解析**:在不做 Elasticsearch 语言计划拼装的前提下,产出可供检索层、重排层与调试界面消费的**结构化事实**(规范化文本、检测语言、可选翻译、文本与 CLIP 向量、分词与关键词、可选的样式意图与标题排除配置等)。下面按**当前实现**说明策略与数据流,便于与 `search/`、`context/`、`frontend/` 对照阅读。
  4 +
  5 +---
  6 +
  7 +## 包内文件与职责
  8 +
  9 +| 文件 | 作用 |
  10 +|------|------|
  11 +| `query_parser.py` | 入口 `QueryParser`:编排规范化、改写、语言检测、异步翻译与向量、分词、关键词、意图与排除检测;定义 `ParsedQuery`。 |
  12 +| `tokenization.py` | 轻量分词、文本规范化、`TokenizedText` 与按请求复用的 `QueryTextAnalysisCache`(模型分词与语言提示、粗细分词策略)。 |
  13 +| `keyword_extractor.py` | `KeywordExtractor`:中文走 HanLP 分词 + 词性名词串;英文走 spaCy 核心词;`collect_keywords_queries` 汇总 `base` 与各翻译语种。 |
  14 +| `english_keyword_extractor.py` | `EnglishKeywordExtractor`:`en_core_web_sm` + 依存/名词块规则,产出短字符串供检索侧关键词子句使用。 |
  15 +| `language_detector.py` | 脚本优先 + Lingua 的通用语言检测(与 `QueryParser` 的英文 ASCII 快路径配合使用)。 |
  16 +| `query_rewriter.py` | 基于配置词典的查询改写与规范化。 |
  17 +| `style_intent.py` | 从配置加载样式意图词表,对查询变体做候选匹配,产出 `StyleIntentProfile`。 |
  18 +| `product_title_exclusion.py` | 从配置加载标题排除规则,对多路查询文本做触发词匹配,产出 `ProductTitleExclusionProfile`。 |
  19 +
  20 +公开符号见 `query/__init__.py`(`QueryParser`、`ParsedQuery`、`KEYWORDS_QUERY_BASE_KEY` 等)。
  21 +
  22 +---
  23 +
  24 +## 解析产物:`ParsedQuery`
  25 +
  26 +`ParsedQuery` 是单次 `parse()` 的权威结果容器,字段含义与下游约定如下。
  27 +
  28 +- **`original_query` / `query_normalized` / `rewritten_query`**:分别为原始输入、规范化后、词典改写后的主查询文本;后续翻译、向量、默认分词与 `base` 关键词均以**改写后的 `rewritten_query`(在代码变量中常名为 `query_text`)**为基准。
  29 +- **`detected_language`**:解析时认定的源语言代码;若检测为 `unknown` 或空,则回退到 `SearchConfig.query_config.default_language`。
  30 +- **`translations`**:键为**目标语言代码**(如 `zh`、`en`),值为翻译服务返回的字符串;仅包含本次请求实际需要的目标语种(见下文翻译目标推导)。
  31 +- **`query_vector` / `image_query_vector`**:分别为 BGE 类文本向量与 CLIP 文本向量(维度由各自编码服务决定);未生成或未在超时内完成则为 `None`。
  32 +- **`query_tokens`**:对**改写后主查询**做分词后的字符串列表,供例如 KNN 参数按 token 数分支等逻辑使用;分词路径由 `QueryTextAnalysisCache` 决定(纯拉丁英文可走轻量分词,含汉字则走 HanLP)。
  33 +- **`keywords_queries`**:与「主查询 + 各翻译变体」平行的**关键词子查询**映射:键 `base`(常量 `KEYWORDS_QUERY_BASE_KEY`)对应源语言侧关键词串,其它键与 `translations` 的语种键一致。空串或无法提取的条目**不会写入**字典。
  34 +- **`style_intent_profile` / `product_title_exclusion_profile`**:可选的理解结果;是否生效完全由 `config.yaml` 中 `query_config` 的对应开关与词表/规则决定。
  35 +- **`_text_analysis_cache`**:单次解析内的分词与语言提示缓存,**不参与序列化**,仅供同一次 `parse` 内各检测器复用,避免对同一文本重复调用 HanLP。
  36 +
  37 +与重排相关的文本选择由独立函数 `rerank_query_text()` 完成:检测为 `zh` 或 `en` 时始终用原始查询;其它语言优先英译再中译,见 `query_parser.py` 中实现。
  38 +
  39 +---
  40 +
  41 +## `QueryParser.parse()` 的执行顺序与策略
  42 +
  43 +解析主流程在 `QueryParser.parse()` 中实现。整体目标是:在**共享等待预算**下并行完成翻译与向量请求,同时尽量减少主线程上重复、昂贵的分词与 NLP 调用,并把结果写入可选的 `context`(请求上下文)供日志与 `debug_info` 使用。
  44 +
  45 +### 1. 规范化与改写
  46 +
  47 +- 使用 `QueryNormalizer` 得到 `query_normalized` 并可选写入 `context.store_intermediate_result('query_normalized', ...)`。
  48 +- 若配置了改写词典,则用 `QueryRewriter` 可能更新 `query_text`;改写成功时记录 `rewritten_query` 与告警。
  49 +
  50 +### 2. 语言检测:通用路径与英文 ASCII 快路径
  51 +
  52 +- **快路径**:当「活跃语种集合」仅为 `en` 与 `zh` 的子集时(活跃集合取 `target_languages` 归一化结果,若为空则回退到 `query_config.supported_languages`),且当前查询为**纯 ASCII、含字母、不含汉字**,则**直接判定为 `en`**,不再调用 `LanguageDetector`(避免 Lingua 等开销)。逻辑见 `_detect_query_language()` 与 `_is_ascii_latin_query()`。
  53 +
  54 +```303:317:query/query_parser.py
  55 + def _detect_query_language(
  56 + self,
  57 + query_text: str,
  58 + *,
  59 + target_languages: Optional[List[str]] = None,
  60 + ) -> str:
  61 + normalized_targets = self._normalize_language_codes(target_languages)
  62 + supported_languages = self._normalize_language_codes(
  63 + getattr(self.config.query_config, "supported_languages", None)
  64 + )
  65 + active_languages = normalized_targets or supported_languages
  66 + if active_languages and set(active_languages).issubset({"en", "zh"}):
  67 + if self._is_ascii_latin_query(query_text):
  68 + return "en"
  69 + return self.language_detector.detect(query_text)
  70 +```
  71 +
  72 +- **通用路径**:`LanguageDetector` 先按 Unicode 脚本返回明确语种(如汉字块即 `zh`),否则用 Lingua 在一大组语言中判别,见 `language_detector.py`。
  73 +
  74 +检测最终结果写入 `context.store_intermediate_result('detected_language', ...)`(若提供 `context`)。
  75 +
  76 +### 3. 按请求分词缓存与语言提示
  77 +
  78 +每次 `parse` 会新建 `QueryTextAnalysisCache(tokenizer=self._tokenizer)`,并对**原始串、规范化串、改写后串**调用 `set_language_hint(..., detected_lang)`,使后续对同一文本的 `get_tokenizer_result` / `get_tokenized_text` 能按语言选择**是否调用 HanLP**。
  79 +
  80 +### 4. HanLP 模型(与 `KeywordExtractor` 对齐)
  81 +
  82 +`QueryParser` 默认构建的 `self._tokenizer` 为 HanLP 预训练分词模型 **`FINE_ELECTRA_SMALL_ZH`**,并开启 `output_spans=True`,以便与关键词提取共用「带偏移的分词结果」。
  83 +
  84 +```237:245:query/query_parser.py
  85 + def _build_tokenizer(self) -> Callable[[str], Any]:
  86 + """Build the tokenizer used by query parsing. No fallback path by design."""
  87 + if hanlp is None:
  88 + raise RuntimeError("HanLP is required for QueryParser tokenization")
  89 + logger.info("Initializing HanLP tokenizer...")
  90 + tokenizer = hanlp.load(hanlp.pretrained.tok.FINE_ELECTRA_SMALL_ZH)
  91 + tokenizer.config.output_spans = True
  92 + logger.info("HanLP tokenizer initialized")
  93 + return tokenizer
  94 +```
  95 +
  96 +`KeywordExtractor` 在未注入自定义 `tokenizer` 时同样加载 **`FINE_ELECTRA_SMALL_ZH`**,并额外加载 **`CTB9_POS_ELECTRA_SMALL`** 做词性标注;二者在「中文路径」上语义一致,便于复用 `tokenizer_result`。
  97 +
  98 +### 5. 异步富集:翻译、文本向量、CLIP 文本向量
  99 +
  100 +- 翻译目标:`translation_targets = normalized_targets` 中**去掉与检测源语言相同**的代码后的列表(例如源为 `en` 且索引语言为 `["en","zh"]` 时只翻 `zh`)。
  101 +- 翻译模型名:由 `_pick_query_translation_model()` 根据「源语言是否在索引语言内」及 `zh↔en` 等分支从 `QueryConfig` 选取。
  102 +- 当 `generate_vector` 为真且配置开启文本嵌入时,向线程池提交 `text_encoder.encode([query_text], ...)`;当配置了 `image_embedding_field` 时提交 `image_encoder.encode_clip_text(query_text, ...)`。
  103 +- 线程池:`ThreadPoolExecutor`,`max_workers` 为 `min(任务数, 4)` 与至少 1。
  104 +- **提交顺序**:先尽可能提交所有异步任务,再在主线程上做「与异步重叠」的轻量工作(见下一节),最后 `concurrent.futures.wait(..., timeout=budget_sec)`。超时未完成的任务会记 warning,并 `shutdown(wait=False)` 不阻塞关闭线程池。
  105 +
  106 +等待预算(毫秒)来自 `QueryConfig`:
  107 +
  108 +- 源语言在索引语言内:`translation_embedding_wait_budget_ms_source_in_index`
  109 +- 否则:`translation_embedding_wait_budget_ms_source_not_in_index`
  110 +
  111 +完成每个 future 后打 `Async enrichment task finished` 日志(含 `elapsed_ms`,为从提交到完成的大致墙钟时间)。
  112 +
  113 +### 6. 主查询分词与「base」关键词(与异步重叠)
  114 +
  115 +在异步任务已提交之后、`wait()` 之前,当前实现会:
  116 +
  117 +1. 通过 `text_analysis_cache.get_tokenizer_result(query_text)` 得到分词结果,再 `extract_token_strings` 得到 **`query_tokens`**;
  118 +2. 调用 `KeywordExtractor.extract_keywords(query_text, language_hint=detected_lang, tokenizer_result=...)` 得到 **`keywords_base_query`**(若失败则日志告警,base 关键词可能为空)。
  119 +
  120 +这样主线程在等翻译/向量时,已并行完成源侧分词与源侧关键词的大部分工作。
  121 +
  122 +### 7. 等待结束后的关键词汇总与检测器
  123 +
  124 +`wait()` 返回后:
  125 +
  126 +- 若有翻译结果,写入 `context.store_intermediate_result("translations", translations)`,并对每条翻译 `text_analysis_cache.set_language_hint(result, lang)`,保证后续对该翻译串的分词/关键词走正确语言路径。
  127 +- `collect_keywords_queries(...)` 合并 **`base`**(可传入已算好的 `base_keywords_query` 避免重复抽取)与各翻译语种的关键词,得到 **`keywords_queries`**;成功时 `context.store_intermediate_result("keywords_queries", keywords_queries)` 并打 `Keyword extraction completed` 日志。
  128 +- 构造带 `_text_analysis_cache` 的 `ParsedQuery` 草稿,依次调用 `StyleIntentDetector.detect` 与 `ProductTitleExclusionDetector.detect`,再把完整 `ParsedQuery` 返回。
  129 +
  130 +解析阶段会打聚合耗时日志 `Query parse stage timings`,字段含义为:
  131 +
  132 +- **`before_wait_ms`**:从解析开始计时点到进入 `wait()` 之前的主线程耗时(含规范化、改写、语言检测、提交异步任务、主查询分词、base 关键词等);
  133 +- **`async_wait_ms`**:`wait()` 阻塞时间;
  134 +- **`base_keywords_ms`**:base 关键词抽取耗时;
  135 +- **`keyword_tail_ms`**:`collect_keywords_queries` 及前后尾部逻辑中关键词相关部分的主要耗时;
  136 +- **`tail_sync_ms`**:`wait()` 之后整段同步尾巴(含关键词汇总、两检测器、写中间结果等)。
  137 +
  138 +---
  139 +
  140 +## 分词与 `QueryTextAnalysisCache`
  141 +
  142 +### `get_tokenizer_result`:何时走 HanLP,何时走轻量分词
  143 +
  144 +- 若未配置模型 `tokenizer`,直接返回空列表路径的轻量结果(由上层避免依赖)。
  145 +- 若根据**该文本的语言提示**与**是否含汉字**判断不需要模型:返回 `simple_tokenize_query` 的列表(字符串 token),**不调用 HanLP**。
  146 +- 否则对该文本调用一次 `self.tokenizer(text)`(HanLP),结果按文本缓存,同一次 `parse` 内重复访问同一字符串不会重复推理。
  147 +
  148 +核心判断在 `_should_use_model_tokenizer`:**语言提示为 `zh` 时,仅当文本含汉字才用模型**;非 `zh` 提示时,仅当文本含汉字才用模型。因此纯英文主查询在提示为 `en` 时走轻量分词;中文翻译串在 `set_language_hint(..., "zh")` 且含汉字时走 HanLP。
  149 +
  150 +### `coarse_tokens` 与 `fine_tokens`:`TokenizedText`
  151 +
  152 +- **`fine_tokens`**:来自 `extract_token_strings(get_tokenizer_result(...))`,在中文路径上即 HanLP 分词后的词串(已按规范化键去重保序)。
  153 +- **`coarse_tokens`**:由 `_build_coarse_tokens` 决定。若语言提示为 **`zh`**,或文本含汉字且已有 `tokenizer_tokens`,则 **粗粒度 token 与 fine 一致**(即采用模型分词粒度,而不用「整段 CJK 连成一项」的纯正则策略)。否则使用 `simple_tokenize_query`(适合拉丁词、数字、带连字符/撇号的英文词形)。
  154 +
  155 +```92:103:query/tokenization.py
  156 +def _build_coarse_tokens(
  157 + text: str,
  158 + *,
  159 + language_hint: Optional[str],
  160 + tokenizer_tokens: Sequence[str],
  161 +) -> List[str]:
  162 + normalized_language = normalize_query_text(language_hint)
  163 + if normalized_language == "zh" or (contains_han_text(text) and tokenizer_tokens):
  164 + # Chinese coarse tokenization should follow the model tokenizer rather than a
  165 + # regex that collapses the whole sentence into one CJK span.
  166 + return list(_dedupe_preserve_order(tokenizer_tokens))
  167 + return _dedupe_preserve_order(simple_tokenize_query(text))
  168 +```
  169 +
  170 +- **`candidates`**:在 fine、coarse、两类 n-gram 短语(上限由 `max_ngram` 控制)以及整句 `normalized_text` 上合并去重,供 `StyleIntentDetector`、`ProductTitleExclusionDetector` 等做子串/短语级匹配。
  171 +
  172 +`tokenize_text()` 是对单次无缓存场景的薄封装:内部新建 `QueryTextAnalysisCache` 再 `get_tokenized_text`。
  173 +
  174 +---
  175 +
  176 +## 关键词提取:`KeywordExtractor` 与 `collect_keywords_queries`
  177 +
  178 +### 路由规则
  179 +
  180 +`extract_keywords` 根据 `language_hint` 分支:
  181 +
  182 +- **`en`**:完全交给 `EnglishKeywordExtractor`(spaCy),**不使用** HanLP 分词结果做 POS 名词筛选(即使调用方传入 `tokenizer_result` 也会被忽略在该路径内)。
  183 +- **`zh`**:使用 HanLP 分词结果(优先复用传入的 `tokenizer_result`),再对词序列跑 `CTB9_POS_ELECTRA_SMALL`,保留**长度 ≥ 2 且词性以 `N` 开头**的词;非连续名词之间插入空格拼接成一条字符串(与 ES 侧 `keywords_query` 的用法一致)。
  184 +- **其它非空语言码**:当前实现返回空串,即**不为该语种生成关键词子句**(由调用方决定是否跳过)。
  185 +
  186 +### `collect_keywords_queries`
  187 +
  188 +- 键 **`base`**:对应 `rewritten_query` 的关键词;若调用方已预先计算 `base_keywords_query` 则直接写入,避免重复抽取。
  189 +- 其它键:与 `translations` 中每个非空语种一一对应,语言码归一化为小写。
  190 +- 全程可传入 `text_analysis_cache`,以便 `get_tokenizer_result` 命中缓存并与检测器共享分词结果。
  191 +
  192 +常量 `KEYWORDS_QUERY_BASE_KEY` 的值为字符串 **`"base"`**,与检索构建里读取的字段一致。
  193 +
  194 +---
  195 +
  196 +## 英文关键词:`EnglishKeywordExtractor`
  197 +
  198 +- 依赖 **spaCy** 模型 **`en_core_web_sm`**,加载时关闭 `ner`、`textcat` 以减轻开销;加载失败时记录 warning 并走基于 `simple_tokenize_query` 的回退策略。
  199 +- 主路径用依存句法与名词块规则收集一小组「核心词」候选(如直接宾语名词、部分 ROOT 名词/专有名词、INTJ 结构下的宾语等),并处理价格/目的介词宾语降级、人口学名词(如 `women`)弱化、尺寸类 ROOT 与主语搭配等边界情况。
  200 +- 使用 `_project_terms_to_query_tokens` 将 spaCy 词形映射回查询中的**表面分词**(例如复合词 `t-shirt`),避免在关键词串中出现被错误切断的片段。
  201 +
  202 +最终返回**最多三个词**的空格连接字符串,用于检索侧第二层 `combined_fields` 的紧凑查询(见下节)。
  203 +
  204 +---
  205 +
  206 +## 与检索层的关系(消费方摘要)
  207 +
  208 +`ParsedQuery.keywords_queries` 由 `search/es_query_builder.py` 读取:在构建某一语言的 lexical 子句时,除主 `combined_fields`(完整 `query`)外,若存在非空的 `keywords_query` 且与主查询不同,会追加第二个 `combined_fields`,使用单独的 `minimum_should_match`(由 builder 的 `keywords_minimum_should_match` 配置)和较低 boost,从而在**不替代全文查询**的前提下加强核心词匹配。
  209 +
  210 +`query_tokens` 在同文件中间接影响例如带文本向量时的 KNN 分支参数(按 token 数量选用长查询的 k / num_candidates 等)。具体字段与 boost 以 `ESQueryBuilder` 当前实现为准。
  211 +
  212 +---
  213 +
  214 +## 样式意图与标题排除(简要)
  215 +
  216 +- **`StyleIntentRegistry` / `StyleIntentDetector`**:从 `QueryConfig.style_intent_terms` 等加载意图定义;`detect` 时按中英变体取查询文本,经 `tokenize_text` 或缓存得到 `TokenizedText`,在 `candidates` 上与配置同义词表匹配,输出 `StyleIntentProfile`(含 `query_variants` 与命中意图列表)。
  217 +- **`ProductTitleExclusionRegistry` / `ProductTitleExclusionDetector`**:从 `QueryConfig.product_title_exclusion_rules` 加载规则;对 `original_query`、`query_normalized`、`rewritten_query` 及所有 `translations` 去重后分词匹配触发词,输出 `ProductTitleExclusionProfile`。
  218 +
  219 +二者均依赖 `tokenization` 与可选的 HanLP,启用与否由配置项控制。
  220 +
  221 +---
  222 +
  223 +## 可观测性与调试
  224 +
  225 +当 `QueryParser.parse(..., context=...)` 传入请求上下文时,典型中间结果包括:
  226 +
  227 +- `query_normalized`、`rewritten_query`、`detected_language`、`query_tokens`
  228 +- `translation_{lang}`、`translations`
  229 +- `keywords_queries`
  230 +- `query_vector_shape`、`image_query_vector_shape`
  231 +- `style_intent_profile`、`product_title_exclusion_profile`
  232 +
  233 +搜索主流程在 `search/searcher.py` 中会把解析结果写入 `QueryAnalysisResult`(含 **`keywords_queries`**),并在 `debug=true` 时把 `query_analysis` 挂到响应的 `debug_info`;前端调试页在 `frontend/static/js/app.js` 中展示 **Translations** 与 **Keywords Queries** 等块,便于与翻译结果并列查看。
  234 +
  235 +---
  236 +
  237 +## 依赖与环境提示
  238 +
  239 +- **HanLP**:分词与中文词性标注;模型名以本文与源码为准(`FINE_ELECTRA_SMALL_ZH` + `CTB9_POS_ELECTRA_SMALL`)。
  240 +- **spaCy**:英文关键词路径需要可导入的 **`en_core_web_sm`**(若缺失则英文关键词退化为轻量规则)。
  241 +- **Lingua**:通用语言检测(在英文 ASCII 快路径不适用时参与拉丁语系判别)。
  242 +
  243 +运行与测试时请使用项目约定的虚拟环境(见仓库根目录 `CLAUDE.md` / `activate.sh`),避免系统 Python 缺少上述依赖。
  244 +
  245 +---
  246 +
  247 +## 扩展与测试
  248 +
  249 +- 单元测试中与解析、分词、意图相关的用例分布在 `tests/test_query_parser_mixed_language.py`、`tests/test_tokenization.py`、`tests/test_style_intent.py`、`tests/test_product_title_exclusion.py` 等文件中;修改分词或关键词策略时应同步更新或新增测试,以保持与本文描述一致。
  250 +
  251 +若新增语种或改写语言检测策略,应同步审视:`QueryParser._detect_query_language`、`QueryTextAnalysisCache._should_use_model_tokenizer`、`KeywordExtractor.extract_keywords` 中非 `zh`/`en` 分支,以及 ES 侧是否应为新语种生成 `keywords_query`。
... ...
scripts/es_debug_search.py renamed to scripts/evaluation/es_debug_search.py
scripts/eval_search_quality.py renamed to scripts/evaluation/eval_search_quality.py
scripts/evaluation/ff.md 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +
  2 +
  3 +
  4 +- R3 完全相关:该结果的核心意图被满足,标题/副标题/类目/属性不违背意图。
  5 +- R2 部分相关:同品类或相近用途,但规格/材质/年龄段/场景等维度的要求有偏差。
  6 +- R1 不相关:品类/用途不符,或明显错误/违禁/空结果。
  7 +
  8 +
  9 +## 指标说明
  10 +
  11 +- **相关性**:1=低,2=中,3=高。
  12 +- **「仅 3 相关」**:只把打分 3 视为相关;**「2_3 相关」**:把 2 和 3 都视为相关。
  13 +
  14 +| 指标 | 含义 |
  15 +|------|------|
  16 +| **P@5, P@10, P@20, P@50** | 前 K 个结果中「仅 3 相关」的精确率 |
  17 +| **P@5_2_3 ~ P@50_2_3** | 前 K 个结果中「2 和 3 都算相关」的精确率 |
  18 +| **MAP_3** | 仅 3 相关时的 Average Precision(单 query) |
  19 +| **MAP_2_3** | 2 和 3 都相关时的 Average Precision |
  20 +| **AUC_3** | 仅 3 相关、1/2 不相关时,随机相关项排在随机不相关项前的概率 |
  21 +| **AUC_2_3** | 2 和 3 相关、1 不相关时的同上 AUC |
  22 +
... ...
scripts/evaluation/queries/fashion_quries__high_quality.txt.v2.uniq 0 → 100644
... ... @@ -0,0 +1,1046 @@
  1 +abstract print top
  2 +acrylic beanie hat
  3 +acrylic knit hat
  4 +airport outfit
  5 +a-line dress
  6 +a-line skirt
  7 +all-season travel pants
  8 +all-season vest lightweight
  9 +ankle boots
  10 +ankle length dress
  11 +ankle length jeans
  12 +ankle length maxi dress
  13 +ankle pants
  14 +ankle pants wrinkle-free
  15 +ankle socks
  16 +ankle socks white
  17 +anorak jacket
  18 +anti-chafing body glide stick
  19 +anti-chafing gym shorts
  20 +anti-chafing pants
  21 +anti-chafing running shorts
  22 +anti-chafing seamless yoga shorts
  23 +anti-chafing women's running shorts
  24 +arm sleeves
  25 +asymmetrical top
  26 +athleisure compression leggings
  27 +athleisure sports bra
  28 +athleisure track suit
  29 +athletic fit compression shorts
  30 +athletic fit running shorts
  31 +athletic gear
  32 +athletic shorts
  33 +athletic socks
  34 +athletic socks merino wool
  35 +athletic tank top
  36 +athletic tee
  37 +autumn blazer tweed
  38 +autumn trench coat
  39 +baby blanket
  40 +baby onesie
  41 +backpack
  42 +baggy jeans
  43 +balloon sleeve
  44 +balloon sleeve blouse
  45 +bamboo socks
  46 +basic cotton t-shirt
  47 +basic tank top ribbed
  48 +bath robe
  49 +bathrobe
  50 +bathrobe women
  51 +bath towel
  52 +beach cover up
  53 +beach towel
  54 +beach umbrella
  55 +beach vacation cover-up
  56 +beach vacation outfit
  57 +beach vacation swimsuit
  58 +beach wedding dress
  59 +beanie hat
  60 +bed sheets
  61 +beige trench coat
  62 +bell bottoms
  63 +belt
  64 +belted coat
  65 +belted jumpsuit
  66 +belted jumpsuit wide leg
  67 +belted jumpsuit with pockets
  68 +belted kimono robe
  69 +belted linen blend maxi dress
  70 +belted moto jacket
  71 +belted trench coat with pockets
  72 +belted waist trainer
  73 +bikini bottom
  74 +bishop sleeve
  75 +bishop sleeve top
  76 +black boots
  77 +black mini dress
  78 +black tie dress
  79 +blazer
  80 +blue denim jacket
  81 +boat neck sweater
  82 +bodycon dress
  83 +bodysuit
  84 +bohemian maxi dress
  85 +bohemian tassel maxi skirt
  86 +bohemian tunic cotton
  87 +bootcut corduroy pants
  88 +bootcut denim pants for riding boots
  89 +bootcut jeans
  90 +bootcut jeans retro
  91 +bootcut pants
  92 +bootcut pants for cowboy boots
  93 +bootcut pants for winter boots
  94 +bootcut velvet pants
  95 +bootcut yoga pants
  96 +boxer briefs
  97 +boyfriend jeans
  98 +bracelet set
  99 +breathable shorts
  100 +bridesmaid dress
  101 +brown leather boots
  102 +bucket hat
  103 +burgundy dress
  104 +burgundy holiday dress
  105 +burnt orange pants
  106 +business casual blazer
  107 +business casual chinos
  108 +business casual loafers
  109 +business casual women
  110 +business suit
  111 +business travel suit
  112 +butterfly hair clip
  113 +butterfly top
  114 +button down shirt
  115 +button-down shirt
  116 +cable knit sweater
  117 +camisole
  118 +cami top
  119 +canvas tote
  120 +cap
  121 +cap sleeve
  122 +cap sleeve top
  123 +cardigan
  124 +cargo pants
  125 +cargo pants hidden pocket
  126 +cargo skirt
  127 +cashmere blend cardigan
  128 +cashmere cardigan
  129 +cashmere scarf
  130 +cashmere sweater
  131 +cashmere sweater beige
  132 +casual day romper
  133 +casual day tank top
  134 +casual friday polo shirt
  135 +casual pants
  136 +casual polo shirt
  137 +casual weekend outfit
  138 +cat bed
  139 +charcoal gray coat
  140 +checkered skirt
  141 +chelsea boots
  142 +chiffon blouse
  143 +chiffon blouse sheer
  144 +chiffon dress
  145 +chiffon scarf lightweight
  146 +chinos
  147 +chocolate brown boots
  148 +chunky knit sweater
  149 +chunky platform boots
  150 +classic fit blazer
  151 +classic fit polo shirt
  152 +classic trench coat tall
  153 +classic wool coat
  154 +cleaning solution
  155 +closed toe heels
  156 +clutch bag
  157 +coachella outfit
  158 +coat
  159 +cobalt blue dress
  160 +cocktail dress
  161 +cold-shoulder blouse
  162 +cold weather insulated boots
  163 +cold weather wool socks
  164 +colorblock hoodie
  165 +commuter outfits
  166 +compression anti-chafing running leggings
  167 +compression arm sleeves
  168 +compression athletic gear
  169 +compression bra
  170 +compression gym workout running shorts
  171 +compression knee brace
  172 +compression leggings
  173 +compression shorts
  174 +compression stockings
  175 +compression tights
  176 +compression tights winter
  177 +compression top
  178 +Compression Top Spandex
  179 +compression yoga sports bra
  180 +concert outfit
  181 +convertible backpack travel bag
  182 +convertible dress
  183 +convertible hiking pants
  184 +convertible laptop bag
  185 +convertible neck pillow blanket
  186 +convertible pants
  187 +convertible sleeves shirt
  188 +convertible sleeves UPF 50 shirt
  189 +convertible zip-off hiking pants
  190 +corduroy blazer
  191 +corduroy fall pants
  192 +corduroy jacket
  193 +corduroy pants
  194 +corduroy skirt
  195 +corduroy skirt mini
  196 +corset top
  197 +corset top black velvet
  198 +cottagecore floral maxi dress
  199 +cottagecore knit cardigan
  200 +cotton flannel shirt
  201 +cotton-padded jacket
  202 +cotton pajamas
  203 +cotton tank top
  204 +cotton t-shirt
  205 +cotton t-shirt white
  206 +cotton tunic
  207 +couple outfits
  208 +cover-up
  209 +cowboy boots
  210 +cream cardigan
  211 +cream knit sweater
  212 +cream sweater
  213 +crew neck sweatshirt
  214 +crew neck tee
  215 +crochet top
  216 +crop hoodie
  217 +crop length hoodie
  218 +crop length sports bra
  219 +crop top
  220 +crossbody leather handbag
  221 +cruise outfits
  222 +curvy fit belt
  223 +curvy fit high-waisted jeans
  224 +curvy fit maxi dress
  225 +curvy fit skinny jeans
  226 +curvy fit straight leg jeans
  227 +curvy fit stretch jeans
  228 +curvy fit stretch pencil skirt
  229 +curvy fit trousers
  230 +curvy fit wide leg jeans
  231 +cushion insert
  232 +cut-out dress
  233 +cycling shorts
  234 +dark academia blazer
  235 +dark academia plaid trousers
  236 +dark academia wool coat
  237 +date night bodycon dress
  238 +date night dress
  239 +date night mini dress
  240 +Dating outfit
  241 +denim jacket
  242 +denim jacket distressed
  243 +denim jacket oversized
  244 +denim jeans
  245 +denim pants
  246 +denim shirt
  247 +denim shorts
  248 +denim skirt
  249 +denim skirt midi
  250 +distressed denim jacket
  251 +distressed jeans
  252 +ditsy floral dress
  253 +dog blanket
  254 +dog coat
  255 +dog crate mat
  256 +dog harness
  257 +dog leash
  258 +dog towel
  259 +dog toy
  260 +dog treat
  261 +double breasted coat
  262 +down jacket
  263 +down parka
  264 +down vest
  265 +dress
  266 +dress sandals
  267 +dress shirt
  268 +duffle bag
  269 +dusty rose dress
  270 +dusty rose silk slip dress
  271 +dusty rose velvet cocktail dress
  272 +dusty rose velvet ribbon
  273 +dusty rose velvet scrunchie
  274 +dusty rose velvet silk dress
  275 +dusty rose velvet slip skirt
  276 +early autumn corduroy jacket
  277 +earthy tones olive
  278 +earthy tones outfit
  279 +electric blue mini skirt
  280 +embroidered blouse
  281 +emerald green top
  282 +ergonomic office chair
  283 +evening formal gown
  284 +evening formal heels
  285 +evening gown
  286 +face mask fashion
  287 +fall cardigan cozy
  288 +fall denim jacket
  289 +fall transitional trench coat
  290 +fanny pack
  291 +fathers day shirt
  292 +faux fur coat
  293 +faux leather clutch bag
  294 +faux leather jacket
  295 +faux leather jacket cropped
  296 +faux leather jacket moto style
  297 +faux leather leggings
  298 +faux leather leggings matte
  299 +faux leather moto jacket
  300 +faux leather moto jacket belted
  301 +faux leather pants
  302 +faux leather skirt
  303 +faux leather wallet
  304 +festival concert crop top
  305 +festival concert jumpsuit
  306 +festival outfit
  307 +field jacket
  308 +first date outfit
  309 +fisherman knit
  310 +fisherman knit sweater
  311 +fishing shirt
  312 +fishing shirt long sleeve
  313 +fishnet top
  314 +flannel shirt
  315 +flare blouse
  316 +flare jeans
  317 +flare pants
  318 +flare pants velvet
  319 +flare sleeved blouse
  320 +fleece jacket
  321 +fleece jacket winter
  322 +fleece lined leggings
  323 +fleece-lined leggings
  324 +fleece mid layer
  325 +fleece pullover
  326 +floral blouse
  327 +floral jacket
  328 +floral maxi dress
  329 +flowy chiffon dress
  330 +flutter sleeve
  331 +flutter sleeve top
  332 +formal attire
  333 +formal dress
  334 +formal gown
  335 +four-way stretch black yoga pants
  336 +four-way stretch denim jeans
  337 +four-way stretch elastic band
  338 +four-way stretch maternity leggings
  339 +four-way stretch tall slim fit pants
  340 +four-way stretch yoga pants
  341 +fringe bag
  342 +geometric pattern sweater
  343 +gingham dress
  344 +gingham pattern dress
  345 +gingham picnic dress
  346 +gingham summer dress
  347 +glasses frames
  348 +gold jewelry
  349 +gold necklace
  350 +gold sequin top
  351 +golf shirt
  352 +golf shirt uv protection
  353 +gothic black boots
  354 +gothic lace-up corset top
  355 +gothic velvet dress
  356 +graduation ceremony tailored suit
  357 +graduation dress
  358 +graphic hoodie
  359 +graphic tee
  360 +graphic t-shirt
  361 +graphic t-shirt vintage wash
  362 +gray hoodie
  363 +green cargo pants
  364 +grunge distressed jeans
  365 +grunge flannel shirt
  366 +gym bag
  367 +gym leggings with pocket
  368 +gym outfit
  369 +gym towel
  370 +gym workout compression top
  371 +gym workout running shorts
  372 +gym workout sports bra
  373 +hair towel
  374 +halloween costume ideas
  375 +halter neck top
  376 +hanger space saving
  377 +heels
  378 +hidden pocket fanny pack
  379 +hidden pocket infinity scarf
  380 +hidden pocket passport holder vest
  381 +hidden pocket travel belt
  382 +hidden pocket travel vest
  383 +hidden pocket women's travel vest
  384 +high heel compatible cocktail dress
  385 +high heel compatible dress sandals
  386 +high heel compatible formal dress
  387 +high heel compatible formal jumpsuit
  388 +high heel compatible shoe inserts
  389 +high neck dress
  390 +high rise leggings
  391 +high rise pants
  392 +high rise wide leg pants
  393 +high-waisted denim jeans
  394 +high-waisted denim shorts
  395 +high waisted jeans
  396 +high-waisted jeans
  397 +hiking boots
  398 +hiking outfit
  399 +hiking pants
  400 +hiking pants women
  401 +hiking shirt convertible sleeves
  402 +hiking shoes
  403 +hiking socks
  404 +hiking trail backpack
  405 +hiking trail raincoat
  406 +hippie bell bottoms
  407 +hippie tie-dye dress
  408 +holiday season formal gown
  409 +holiday season velvet dress
  410 +homecoming dress
  411 +homewear
  412 +hooded jacket
  413 +hoodie
  414 +houndstooth coat
  415 +instagram outfit
  416 +insulated base layer
  417 +insulated boots
  418 +insulated gloves
  419 +interview clothes
  420 +invisible socks
  421 +ivory dress
  422 +ivory wedding dress
  423 +jacket
  424 +jeans
  425 +jean shorts
  426 +jeggings
  427 +jewel tones dress
  428 +jewel tones emerald
  429 +jogger pants
  430 +jumpsuit
  431 +kawaii crop top
  432 +kawaii mini dress
  433 +keyhole top
  434 +khaki green backpack
  435 +khaki green canvas tote
  436 +khaki green cargo pants utility
  437 +khaki green military jacket
  438 +khaki green ripstop convertible pants
  439 +khaki green ripstop fabric trousers
  440 +kids cotton pajamas set
  441 +kids' cotton pajamas set
  442 +kimono robe
  443 +knee brace
  444 +knee high boots
  445 +knit cardigan
  446 +knit hat
  447 +knit scarf
  448 +knit sweater
  449 +knitwear
  450 +lace bralette
  451 +lace dress
  452 +lantern sleeve
  453 +lantern sleeve top
  454 +laptop backpack
  455 +laptop bag
  456 +layering hoodie
  457 +leather bag
  458 +leather handbag
  459 +leather jacket
  460 +leather sandals
  461 +leather shoes
  462 +leather skirt
  463 +leggings
  464 +leopard print blouse
  465 +light jacket
  466 +lightweight jacket
  467 +lightweight scarf
  468 +linen blend maxi dress
  469 +linen blend trousers
  470 +linen dress
  471 +linen fabric breathable
  472 +linen pants
  473 +linen shorts
  474 +linen short set
  475 +linen shorts summer
  476 +linen trousers
  477 +litter box
  478 +loafers
  479 +long blazer
  480 +long coat
  481 +long sleeve top
  482 +long tunic top
  483 +loose fit boyfriend jeans
  484 +loose fit cap
  485 +loose fit cardigan cashmere
  486 +loose fit graphic hoodie streetwear
  487 +loose fit graphic print t-shirt
  488 +loose fit graphic t-shirt
  489 +loose fit knit sweater
  490 +loose fit summer pure cotton t-shirt
  491 +loose fit tunic
  492 +lounge wear bodysuit
  493 +lounge wear pajamas set
  494 +low rise bikini bottom
  495 +low rise jeans
  496 +low rise shorts
  497 +maternity casual friday polo shirt
  498 +maternity dress
  499 +maternity nursing bra
  500 +maternity pillow
  501 +maternity robe silk
  502 +maternity support band leggings
  503 +maternity support leggings
  504 +maternity support leggings black
  505 +maternity swimsuit
  506 +maternity tall trousers
  507 +maternity trousers
  508 +maternity wear
  509 +maternity wide leg denim jeans
  510 +maternity yoga Pants
  511 +mauve pink cardigan
  512 +maxi dress
  513 +maxi skirt
  514 +men's athletic running shorts
  515 +men's dress shirt
  516 +men's running shorts
  517 +men's suit vest
  518 +merino wool base layer
  519 +merino wool glove liners
  520 +merino wool hiking socks
  521 +merino wool ski socks
  522 +merino wool socks
  523 +merino wool socks hiking
  524 +merino wool thermal base layer top
  525 +merino wool thermal leggings base layer
  526 +merino wool thermal underwear
  527 +mesh athletic shorts
  528 +mesh athletic tee
  529 +mesh shirt
  530 +mesh shoes
  531 +metallic leggings
  532 +Microfiber Robe
  533 +Microfiber Towel Quick-Dry
  534 +midi cocktail dress
  535 +midi dress
  536 +mid rise bootcut jeans
  537 +mid rise skirts
  538 +mid-season waterproof shell jacket
  539 +military field Jacket
  540 +military green jacket
  541 +military jacket
  542 +mini dress
  543 +minimalist high rise pants
  544 +minimalist linen dress
  545 +minimalist linen trousers
  546 +minimalist wallet
  547 +mini skirt
  548 +mock neck shirt
  549 +modest long sleeve top
  550 +modest swimsuit one-piece
  551 +moisture-wicking cycling jersey
  552 +moisture-wicking golf shirt
  553 +moisture-wicking golf shirt men's
  554 +moisture-wicking gym towel
  555 +moisture-wicking hiking trail t-shirt
  556 +mom outfit
  557 +monochrome outfit
  558 +mother bride dress
  559 +mothers day gift
  560 +moto jacket
  561 +mustard yellow top
  562 +nautical pea coat
  563 +nautical striped sweater
  564 +navy blazer
  565 +navy blue cashmere beanie
  566 +navy blue cashmere blanket
  567 +navy blue cashmere blend scarf
  568 +navy blue cashmere scarf
  569 +navy blue cashmere winter coat
  570 +neon pink crop top
  571 +neutral tones beige
  572 +neutral tones clothing
  573 +new mom clothes
  574 +new years eve dress
  575 +no show socks
  576 +notch lapel blazer
  577 +nurse scrubs
  578 +nursing bra
  579 +nursing dress
  580 +nylon raincoat waterproof
  581 +nylon running shorts
  582 +nylon shorts
  583 +odor control athletic headbands
  584 +odor control athletic socks
  585 +odor control men's athletic socks
  586 +odor control running shoes insoles
  587 +odor control shoe spray
  588 +odor control trash can
  589 +office wear
  590 +office wear pencil skirt
  591 +office wear sheath dress
  592 +off-shoulder dress
  593 +off shoulder top
  594 +off white sneakers
  595 +olive green jacket
  596 +olive jacket
  597 +olive utility jacket
  598 +one-piece swimsuit
  599 +one-shoulder top
  600 +organic cotton baby blanket
  601 +organic cotton baby wear
  602 +organic cotton crew neck tee
  603 +organic cotton crew neck tee vintage
  604 +organic cotton crew neck t-shirt
  605 +organic cotton t-shirt
  606 +organic cotton underwear
  607 +organic cotton washcloth
  608 +organic cotton white t-shirt
  609 +organza top
  610 +oversized cardigan
  611 +oversized hoodie
  612 +oversized knit sweater
  613 +oversized puffer vest
  614 +oversized pullover hoodie
  615 +oversized scarf
  616 +oversized t-shirt
  617 +oversized turtleneck sweater
  618 +oversized zip up hoodie
  619 +paisley print
  620 +paisley print boho
  621 +pajamas
  622 +pajamas set
  623 +palazzo pants
  624 +pants
  625 +parent-child matching outfits
  626 +party dress
  627 +pastel purple sweater
  628 +patterned jumpsuit
  629 +patterned scarf
  630 +pea coat
  631 +peak lapel formal
  632 +pencil skirt
  633 +pencil skirt stretch
  634 +pet camera
  635 +peter pan collar
  636 +petite a-line skirt
  637 +petite ankle boots
  638 +petite jeans
  639 +petite summer dress
  640 +petite summer linen shorts
  641 +petite tailored business suit
  642 +petite tailored suit jacket
  643 +petite tailored trousers wrinkle-free
  644 +petite wedding guest midi dress
  645 +photoshoot outfit
  646 +pink sweater
  647 +pink sweater aesthetic
  648 +plaid pants
  649 +plaid skirt
  650 +plaid trousers
  651 +platform boots
  652 +platform sneakers
  653 +play clothes
  654 +pleated tennis skirt
  655 +plus size blouse
  656 +plus size denim jeans
  657 +plus size petite jeans
  658 +plus size swim dress
  659 +plus size tunic tops
  660 +plus size tunic tops for leggings
  661 +plus size winter fleece lined leggings
  662 +plus size winter gloves
  663 +plus size winter hiking boots
  664 +plus size winter parka jacket
  665 +plus-size women's clothing
  666 +polarized sunglasses
  667 +polka dot dress
  668 +polo shirt
  669 +polyester fleece jacket
  670 +polyester running Shorts
  671 +polyester shorts
  672 +postpartum outfit
  673 +pregnancy pillow
  674 +preppy plaid skirt
  675 +preppy plaid tennis skirt
  676 +preppy sweater vest
  677 +prom dress
  678 +puffer jacket
  679 +puffer vest
  680 +puff sleeve blouse
  681 +puff sleeve dress
  682 +pullover hoodie
  683 +punk faux leather skirt
  684 +punk studded belt
  685 +pure cotton t-shirt
  686 +pure linen bath towel
  687 +pure linen short set
  688 +pure linen short set beach vacation
  689 +pure linen summer dress maxi
  690 +pure linen tablecloth
  691 +pure linen wide leg pants
  692 +quick-dry shirt
  693 +quick-dry towel
  694 +quilted jacket
  695 +rain boots
  696 +raincoat
  697 +rain jacket
  698 +rainy season anorak jacket
  699 +rainy season waterproof boots
  700 +rayon blouse
  701 +rayon blouse print
  702 +rayon jumpsuit
  703 +rayon jumpsuit summer
  704 +Recycled Fabric Hoodie
  705 +recycled fabric sneakers
  706 +recycled polyester bag
  707 +recycled polyester gym bag
  708 +recycled polyester laptop sleeve
  709 +recycled polyester reusable shopping bag
  710 +recycled polyester running jacket
  711 +recycled polyester swim shorts
  712 +recycled polyester waterproof shell jacket
  713 +red silk blouse
  714 +relaxed fit denim jacket
  715 +relaxed fit denim shorts
  716 +relaxed fit sweater
  717 +relaxed fit sweatpants
  718 +resort wear
  719 +retro flare jeans
  720 +retro patterned jumpsuit
  721 +ribbed tank top
  722 +riding boots
  723 +ripstop cargo trousers
  724 +robe
  725 +romantic chiffon blouse
  726 +romantic puff sleeve blouse
  727 +romantic silk blouse
  728 +romper
  729 +rose gold jewelry
  730 +round sunglasses
  731 +ruffle skirt
  732 +ruffle sleeve
  733 +ruffle sleeve top
  734 +running jacket
  735 +running leggings
  736 +running shorts
  737 +running shorts with lining
  738 +rust colored sweater
  739 +rust midi skirt
  740 +sage green lounge set
  741 +sandals
  742 +satin cami top
  743 +satin robe
  744 +scarf
  745 +scented candle
  746 +school uniform
  747 +school uniform blazer
  748 +school uniform polo shirt
  749 +scoop neck tank
  750 +scrunchie
  751 +seamless yoga leggings
  752 +semi-formal evening gown
  753 +sequin cocktail dress
  754 +shaving razor
  755 +shawl collar cardigan
  756 +sheath dress
  757 +sheer organza top
  758 +shell jacket
  759 +sherpa jacket
  760 +shimmering metallic crop top
  761 +shimmering metallic leggings
  762 +shimmering metallic leggings yoga
  763 +shimmering metallic party dress
  764 +shimmering metallic phone case
  765 +shirt
  766 +shoe inserts
  767 +shoe laces
  768 +shorts
  769 +short set
  770 +silk blouse
  771 +silk dress
  772 +silk pajamas
  773 +silk pajamas set
  774 +silk robe
  775 +silk slip dress
  776 +silver metallic heels
  777 +skiing fleece mid layer
  778 +skiing thermal underwear
  779 +skiing trip insulated base layer
  780 +skinny fit jeggings
  781 +skinny fit pants
  782 +skinny jeans
  783 +skinny pants
  784 +ski outfit
  785 +skirt
  786 +skirt suit
  787 +ski socks
  788 +sleeveless dress
  789 +sleeveless summer dress
  790 +slim fit ankle pants
  791 +slim fit blazer wool
  792 +slim fit button-down shirt
  793 +slim fit trousers
  794 +slip dress
  795 +slip on sneakers
  796 +smart casual men
  797 +snake print boots
  798 +sneaker matching ankle socks
  799 +sneaker matching crew socks
  800 +sneaker matching invisible socks
  801 +sneaker matching low cut socks
  802 +sneaker matching no show socks
  803 +sneaker matching shoe laces
  804 +sneakers
  805 +sock boots
  806 +sofa bed
  807 +soft robe
  808 +spaghetti strap cami
  809 +spaghetti strap dress
  810 +Spandex Compression Bra
  811 +spandex cycling shorts
  812 +sports bra
  813 +sports bra high impact
  814 +sports top
  815 +sportswear outfit
  816 +spring blouse floral
  817 +spring lightweight floral jacket
  818 +spring trench coat
  819 +square neck top
  820 +stain-resistant apron cooking
  821 +stain-resistant boys play pants
  822 +stain-resistant kids' play clothes
  823 +stain-resistant kids school uniform
  824 +stain-resistant placemats
  825 +stain-resistant white t-shirt
  826 +stiletto boots
  827 +stiletto heels
  828 +stiletto protectors
  829 +straight leg ankle pants
  830 +straight leg ankle pants office wear
  831 +straight leg ankle pants stretch
  832 +straight leg anti-chafing pants
  833 +straight leg jeans
  834 +straight leg pants
  835 +straight leg trousers work
  836 +straight leg trousers workwear
  837 +strapless dress
  838 +straw hat
  839 +streetwear graphic hoodie
  840 +streetwear hoodie men
  841 +streetwear oversized hoodie
  842 +streetwear zip-up hoodie
  843 +stretch jeans
  844 +stretch jeans straight leg
  845 +striped shirt
  846 +striped shirt navy
  847 +striped sweater
  848 +studded belt
  849 +suede ankle boots
  850 +suede boots
  851 +suede loafers
  852 +suede loafers casual
  853 +suit
  854 +suit jacket
  855 +suit men
  856 +summer quick-dry UPF 50 shirt
  857 +summer strapless dress
  858 +summer sundress floral
  859 +sundress
  860 +sun hat
  861 +sun hat wide brim
  862 +sun protection clothing
  863 +sun protective clothing
  864 +support belt
  865 +sweater
  866 +sweater dress
  867 +sweater vest
  868 +sweatpants
  869 +sweatshirt
  870 +sweatsuit
  871 +sweetheart neckline dress
  872 +swim dress
  873 +swim shorts
  874 +swimsuit
  875 +swim trunks
  876 +tailored shirt
  877 +tailored suit
  878 +tailored suit jacket
  879 +tailored suit slim fit
  880 +tall slim fit business casual blazer
  881 +tall slim fit men's dress shirt
  882 +tall slim fit men's linen shirt
  883 +tall slim fit men's suit vest
  884 +tall slim fit office wear blazer
  885 +tall slim fit tie
  886 +tall slim fit trousers
  887 +tall straight leg pants
  888 +tank top
  889 +tassel maxi skirt
  890 +teacher clothes
  891 +teal blouse
  892 +teal satin blouse
  893 +temperature regulating mattress pad
  894 +temperature regulating pajamas
  895 +temperature regulating pillow
  896 +temperature regulating silk pajamas
  897 +temperature regulating sleepwear
  898 +temperature regulating winter socks
  899 +tennis skirt
  900 +terracotta linen pants
  901 +terracotta pants
  902 +terry cloth bathrobe
  903 +terry cloth shorts
  904 +terry cloth sweatshirt
  905 +thermal base layer
  906 +thermal base layer top
  907 +thermal long sleeve top
  908 +thermal skiing jacket
  909 +thermal underwear
  910 +thigh shorts anti-chafing
  911 +tie
  912 +tie-dye bucket hat
  913 +tie-dye dress
  914 +tie-dye oversized knit sweater
  915 +tie-dye oversized sweatshirt
  916 +tie-dye socks pastel colors
  917 +tie-dye summer maxi dress
  918 +tie-dye water bottle
  919 +tie-waist pants
  920 +tiktok outfit
  921 +toddler crib
  922 +tote bag
  923 +track suit
  924 +track suit quick-dry
  925 +transitional light jacket
  926 +transitional sweater vest
  927 +Travel attire
  928 +travel blazer
  929 +travel blazer lightweight
  930 +travel clothes
  931 +travel lightweight scarf
  932 +travel pants
  933 +travel suit
  934 +travel vest
  935 +travel wrinkle-free pants
  936 +trench coat
  937 +tropical climate breathable shorts
  938 +tropical climate sandals
  939 +Tropical Climate Sandals Leather
  940 +tropical print shirt
  941 +trousers
  942 +trumpet sleeve
  943 +trumpet sleeve top
  944 +t-shirt
  945 +tube top
  946 +tulle overlay skirt
  947 +tulle skirt
  948 +tulle skirt party
  949 +tunic
  950 +tunic top
  951 +tunic tops
  952 +tunic tops loose fit
  953 +turtleneck sweater
  954 +tweed blazer
  955 +two piece set
  956 +ugly christmas sweater
  957 +umbrella
  958 +underwear
  959 +utility cargo pants
  960 +utility cargo skirt
  961 +UV protection face mask
  962 +UV protection fishing shirt
  963 +UV protection gardening hat
  964 +UV protection sun hat
  965 +UV protection women's sun gloves
  966 +vacation outfits
  967 +valentines day outfit
  968 +velvet cocktail party dress
  969 +velvet dress
  970 +velvet heels
  971 +velvet heels formal
  972 +velvet holiday dress
  973 +velvet midi skirt
  974 +velvet skirt
  975 +vest
  976 +vintage denim jacket
  977 +vintage distressed denim jacket
  978 +vintage leather skirt
  979 +viscose cami top
  980 +viscose scarf patterned
  981 +v-neck t-shirt
  982 +waffle knit henley
  983 +waist trainer
  984 +wallet
  985 +waterproof boots
  986 +waterproof hooded jacket
  987 +waterproof raincoat
  988 +waterproof shell jacket
  989 +waterproof spray
  990 +Wearing small clothes
  991 +wedding guest cocktail dress
  992 +wedding guest dress
  993 +wedding guest formal attire
  994 +wedding guest midi dress
  995 +wedding guest slip dress
  996 +western cowboy boots
  997 +western denim shirt
  998 +white cotton t-shirt
  999 +white linen pants
  1000 +wide brim hat
  1001 +wide leg jeans
  1002 +wide leg linen pants
  1003 +wide leg palazzo trousers
  1004 +wide leg pants
  1005 +wide leg trousers
  1006 +window film
  1007 +winter fleece-lined leggings
  1008 +winter gloves
  1009 +Winter outfits
  1010 +winter parka
  1011 +winter parka down
  1012 +winter puffer jacket
  1013 +women's summer maxi dress
  1014 +wool blazer
  1015 +wool blend long coat
  1016 +wool coat
  1017 +wool coat tall
  1018 +wool pea coat
  1019 +wool socks
  1020 +wool winter coat
  1021 +work from home
  1022 +workout clothes
  1023 +workwear trousers
  1024 +wrap dress
  1025 +wrinkle-free business shirt
  1026 +wrinkle-free business travel suit
  1027 +wrinkle-free fabric spray
  1028 +wrinkle-free pants
  1029 +wrinkle-free travel blazer
  1030 +wrinkle-free travel dress
  1031 +wrinkle-free travel pants
  1032 +wrinkle release spray
  1033 +y2k low-rise baggy jeans
  1034 +y2k low-rise cargo pants
  1035 +y2k low rise jeans
  1036 +y2k tube top
  1037 +yoga leggings
  1038 +yoga mat
  1039 +yoga outfit
  1040 +yoga pants
  1041 +yoga pants high-waisted
  1042 +yoga shorts
  1043 +zebra print pants
  1044 +zipper boots
  1045 +zip-up hoodie
  1046 +zoom shirt
... ...
scripts/evaluation/queries/fashion_quries__high_quality.txt.v2.uniq.trans 0 → 100644
... ... @@ -0,0 +1,1232 @@
  1 +抽象打印顶部
  2 +丙烯酸无檐便帽
  3 +亚克力豆豆帽
  4 +丙烯酸针织帽
  5 +亚克力针织帽
  6 +机场装备
  7 +A字裙
  8 +a字裙
  9 +全季旅行裤
  10 +四季旅行裤
  11 +全季轻便背心
  12 +踝靴
  13 +及踝连衣裙
  14 +及踝牛仔裤
  15 +及膝牛仔裤
  16 +及踝长裙
  17 +齐踝长裙
  18 +脚踝裤
  19 +脚踝裤不起皱
  20 +脚踝长裤无皱纹
  21 +短袜
  22 +白色脚踝袜
  23 +防寒茄克衫
  24 +防擦车身滑杆
  25 +防擦伤运动短裤
  26 +防擦伤裤
  27 +防擦伤长裤
  28 +防擦伤跑步短裤
  29 +防摩擦无缝瑜伽短裤
  30 +防擦伤女式跑步短裤
  31 +臂袖
  32 +不对称陀螺
  33 +运动休闲紧身裤
  34 +运动紧身裤
  35 +运动休闲文胸
  36 +运动休闲运动内衣
  37 +运动休闲运动套装
  38 +运动型紧身短裤
  39 +运动型跑步短裤
  40 +运动装备
  41 +运动短裤
  42 +运动袜
  43 +美利奴羊毛运动袜
  44 +运动背心
  45 +运动T恤
  46 +秋季花呢上衣
  47 +秋季运动夹克
  48 +秋季风衣
  49 +婴儿毯
  50 +婴儿连体衣
  51 +背包
  52 +宽松牛仔裤
  53 +布袋牛仔裤
  54 +气球袖
  55 +气球袖衬衫
  56 +竹制袜子
  57 +竹袜
  58 +基本棉t恤
  59 +基本棉T恤
  60 +基本油箱顶部带肋
  61 +基本款背心罗纹
  62 +浴袍
  63 +女式浴袍
  64 +浴巾
  65 +海滩掩护
  66 +海滩遮盖
  67 +沙滩巾
  68 +沙滩伞
  69 +海滩度假掩盖
  70 +海滩度假装
  71 +海滩度假套装
  72 +海滩度假泳装
  73 +海滩度假泳衣
  74 +沙滩婚纱
  75 +毛线帽
  76 +床单
  77 +米色风衣
  78 +喇叭裤
  79 +腰带
  80 +系带大衣
  81 +皮带外套
  82 +系带连身裤
  83 +阔腿系带连身裤
  84 +带口袋的系带连身裤
  85 +腰带和服长袍
  86 +系带亚麻混纺长裙
  87 +系带摩托车夹克
  88 +带腰带的摩托车夹克
  89 +带口袋的系带风衣
  90 +束腰训练器
  91 +比基尼海滩
  92 +主教袖
  93 +主教袖上衣
  94 +黑色靴子
  95 +黑色迷你连衣裙
  96 +黑色领带裙
  97 +西装外套
  98 +蓝色牛仔夹克
  99 +船领毛衣
  100 +紧身连衣裙
  101 +连体衣
  102 +波西米亚风格的长裙
  103 +波西米亚长裙
  104 +波西米亚流苏长裙
  105 +波西米亚棉质束腰外衣
  106 +波西米亚束腰棉
  107 +短靴灯芯绒长裤
  108 +马靴用短靴牛仔裤
  109 +短靴牛仔裤
  110 +复古短靴牛仔裤
  111 +短靴裤
  112 +开襟长裤
  113 +牛仔靴开叉裤
  114 +冬季靴子的短靴裤
  115 +天鹅绒短靴裤
  116 +短靴瑜伽裤
  117 +四角裤
  118 +平角内裤
  119 +男朋友牛仔裤
  120 +手镯套装
  121 +透气短裤
  122 +伴娘裙
  123 +棕色皮靴
  124 +渔夫帽
  125 +酒红色连衣裙
  126 +酒红色节日连衣裙
  127 +勃艮第节日连衣裙
  128 +焦橙色裤子
  129 +烧焦的橙色裤子
  130 +商务休闲夹克
  131 +商务休闲斜纹棉布裤
  132 +商务休闲奇诺
  133 +商务休闲乐福鞋
  134 +商务休闲女性
  135 +商务套装
  136 +商务旅行套装
  137 +蝴蝶发夹
  138 +蝶形上衣
  139 +蝴蝶上衣
  140 +纽扣衬衫
  141 +针织毛衣
  142 +女士背心
  143 +吊带背心
  144 +卡米上衣
  145 +帆布手提包
  146 +帽子
  147 +帽
  148 +帽袖
  149 +帽套顶部
  150 +帽袖上衣
  151 +开襟毛衣
  152 +工装裤
  153 +工装裤隐藏口袋
  154 +载货裙
  155 +羊绒混纺开衫
  156 +羊绒开衫
  157 +羊绒围巾
  158 +羊绒衫
  159 +米色羊绒衫
  160 +米色羊绒毛衣
  161 +休闲日间连身裤
  162 +休闲日服
  163 +休闲日间背心
  164 +休闲日背心
  165 +休闲星期五马球衫
  166 +休闲裤
  167 +休闲马球衫
  168 +休闲Polo衫
  169 +休闲周末装
  170 +猫床
  171 +炭灰色大衣
  172 +炭灰色涂层
  173 +格子裙
  174 +切尔西靴
  175 +雪纺衬衫
  176 +雪纺衬衫透明
  177 +雪纺裙
  178 +雪纺围巾轻盈
  179 +斜纹棉布裤
  180 +巧克力棕色靴子
  181 +厚实针织毛衣
  182 +厚底靴
  183 +经典合身上衣
  184 +经典合身运动夹克
  185 +经典合身马球衫
  186 +经典合身Polo衫
  187 +经典风衣高
  188 +经典羊毛大衣
  189 +清洁溶液
  190 +闭趾高跟鞋
  191 +手拿包
  192 +科切拉服装
  193 +外套
  194 +钴蓝色连衣裙
  195 +鸡尾酒裙
  196 +露肩上衣
  197 +冷肩衬衫
  198 +防寒保暖靴
  199 +寒冷天气隔热靴
  200 +寒冷天气羊毛袜
  201 +拼色连帽衫
  202 +通勤者服装
  203 +紧身防擦伤跑步紧身裤
  204 +压缩臂袖
  205 +压缩式运动装备
  206 +压缩运动装备
  207 +压缩胸罩
  208 +压缩健身房锻炼跑步短裤
  209 +膝关节加压支架
  210 +紧身裤
  211 +紧身短裤
  212 +压力袜
  213 +紧身紧身裤
  214 +冬季紧身裤
  215 +压缩式上衣
  216 +紧身上衣氨纶
  217 +压缩瑜伽运动胸罩
  218 +演唱会服装
  219 +可转换背包旅行包
  220 +敞篷连衣裙
  221 +敞篷登山裤
  222 +敞篷徒步裤
  223 +可转换笔记本电脑包
  224 +可转换颈枕毯
  225 +敞篷裤
  226 +可转换袖衬衫
  227 +可转换袖UPF 50衬衫
  228 +可转换拉链登山裤
  229 +灯芯绒运动夹克
  230 +灯芯绒秋裤
  231 +灯芯绒秋季长裤
  232 +条绒夹克
  233 +灯芯绒长裤
  234 +灯芯绒裙子
  235 +灯芯绒迷你裙
  236 +束身衣上衣
  237 +黑色天鹅绒紧身胸衣上衣
  238 +黑色天鹅绒紧身胸衣
  239 +棉芯印花长裙
  240 +Cottagecore印花长裙
  241 +棉芯针织开衫
  242 +Cottagecore针织开衫
  243 +棉绒布衬衫
  244 +棉袄
  245 +棉睡衣
  246 +棉质背心
  247 +棉背心
  248 +棉质t恤
  249 +白色棉质t恤
  250 +白色棉质T恤
  251 +棉质上衣
  252 +情侣装
  253 +掩盖
  254 +牛仔靴
  255 +奶油色开衫
  256 +奶油色针织毛衣
  257 +奶油针织毛衣
  258 +奶油色毛衣
  259 +圆领运动衫
  260 +圆领T恤
  261 +钩针上衣
  262 +露脐连帽衫
  263 +露脐运动文胸
  264 +及膝运动内衣
  265 +露脐上衣
  266 +斜身皮包
  267 +斜挎包
  268 +游轮服装
  269 +曲线贴合腰带
  270 +曲线合身高腰牛仔裤
  271 +曲线合身的长裙
  272 +修身长裙
  273 +曲线合身的紧身牛仔裤
  274 +修身牛仔裤
  275 +曲线合身的直筒牛仔裤
  276 +曲线合身的弹力牛仔裤
  277 +曲线合身的弹力铅笔裙
  278 +曲线合身的裤子
  279 +修身长裤
  280 +曲线合身阔腿牛仔裤
  281 +修身宽腿牛仔裤
  282 +衬垫衬垫
  283 +镂空连衣裙
  284 +骑行短裤
  285 +深色学术运动夹克
  286 +黑暗学院开拓者
  287 +深色学术格子裤
  288 +深色学院格子长裤
  289 +深色学术羊毛大衣
  290 +约会之夜紧身连衣裙
  291 +约会晚礼服
  292 +约会之夜迷你裙
  293 +约会之夜迷你连衣裙
  294 +约会装
  295 +牛仔夹克
  296 +破旧牛仔夹克
  297 +牛仔夹克破旧
  298 +大号牛仔夹克
  299 +牛仔夹克超大
  300 +牛仔牛仔裤
  301 +牛仔裤
  302 +牛仔衬衫
  303 +牛仔短裤
  304 +牛仔裙
  305 +牛仔裙midi
  306 +牛仔裙Midi
  307 +破旧牛仔夹克
  308 +破旧牛仔裤
  309 +碎花连衣裙
  310 +狗毯
  311 +狗大衣
  312 +狗笼垫
  313 +狗用背带
  314 +狗绳
  315 +狗毛巾
  316 +狗玩具
  317 +狗食
  318 +双排扣大衣
  319 +双排扣外套
  320 +羽绒服
  321 +羽绒背心
  322 +连衣裙
  323 +连衣裙凉鞋
  324 +正装凉鞋
  325 +衬衫
  326 +行李袋
  327 +尘土飞扬的玫瑰色连衣裙
  328 +玫瑰粉连衣裙
  329 +尘土飞扬的玫瑰色丝绸吊带裙
  330 +尘土飞扬的玫瑰色天鹅绒鸡尾酒会礼服
  331 +尘土飞扬的玫瑰天鹅绒缎带
  332 +尘土飞扬的玫瑰天鹅绒发髻
  333 +尘土飞扬的玫瑰色天鹅绒丝绸连衣裙
  334 +尘土飞扬的玫瑰色天鹅绒吊带裙
  335 +初秋灯芯绒夹克
  336 +泥土色调橄榄色
  337 +土色调服装
  338 +土色调套装
  339 +电蓝色迷你裙
  340 +绣花上衣
  341 +祖母绿上衣
  342 +翡翠绿上衣
  343 +符合人体工程学的办公椅
  344 +晚礼服
  345 +晚礼服高跟鞋
  346 +晚礼服
  347 +口罩时尚
  348 +秋季羊毛衫舒适
  349 +秋季舒适开衫
  350 +秋季牛仔夹克
  351 +秋季过渡风衣
  352 +腰包
  353 +父亲节衬衫
  354 +人造毛皮大衣
  355 +人造革手包
  356 +人造皮夹克
  357 +短款人造皮夹克
  358 +摩托风格人造皮夹克
  359 +人造皮革紧身裤
  360 +哑光人造皮革紧身裤
  361 +仿皮哑光紧身裤
  362 +人造皮革摩托车夹克
  363 +人造皮革摩托车夹克,带腰带
  364 +人造皮裤
  365 +人造革长裤
  366 +人造革裙子
  367 +人造皮革钱包
  368 +节日音乐会露顶
  369 +节日音乐会Crop Top
  370 +节日音乐会连身裤
  371 +节日音乐会连体衣
  372 +节日服装
  373 +野战夹克
  374 +初次约会服装
  375 +渔夫针织
  376 +渔夫针织毛衣
  377 +钓鱼衬衫
  378 +长袖钓鱼衫
  379 +钓鱼衫长袖
  380 +渔网上衣
  381 +法兰绒衬衫
  382 +喇叭形上衣
  383 +喇叭牛仔裤
  384 +喇叭裤
  385 +天鹅绒喇叭裤
  386 +丝绒喇叭裤
  387 +喇叭袖衬衫
  388 +抓绒夹克
  389 +冬季羊毛夹克
  390 +羊毛夹克冬季
  391 +羊毛衬里紧身裤
  392 +羊毛中层
  393 +羊毛套头衫
  394 +花衬衫
  395 +花夹克
  396 +印花长裙
  397 +花朵长裙
  398 +飘逸雪纺连衣裙
  399 +颤动袖
  400 +颤振袖顶
  401 +飘逸袖上衣
  402 +礼服
  403 +正装
  404 +礼服
  405 +四向弹力黑色瑜伽裤
  406 +四向弹力牛仔牛仔裤
  407 +四向拉伸弹性带
  408 +四向弹力孕妇紧身裤
  409 +四向弹力高修身长裤
  410 +四向弹力瑜伽裤
  411 +流苏包
  412 +流苏袋
  413 +几何图案毛衣
  414 +条纹连衣裙
  415 +金黄色连衣裙
  416 +条纹野餐裙
  417 +Gingham野餐裙
  418 +条纹夏装
  419 +金黄色连衣裙
  420 +眼镜架
  421 +黄金首饰
  422 +黄金珠宝
  423 +金项链
  424 +金色亮片上衣
  425 +高尔夫球衫
  426 +高尔夫球衫紫外线防护
  427 +哥特式黑色靴子
  428 +哥特式系带紧身胸衣
  429 +哥特式天鹅绒连衣裙
  430 +毕业典礼定制西装
  431 +毕业礼服
  432 +图案连帽衫
  433 +图案T恤
  434 +图案t恤
  435 +复古水洗图案t恤
  436 +图案T恤复古水洗
  437 +灰色连帽衫
  438 +绿色工装裤
  439 +破旧牛仔裤
  440 +破烂牛仔裤
  441 +脏兮兮的法兰绒衬衫
  442 +粗面法兰绒衬衫
  443 +健身包
  444 +带口袋的健身紧身裤
  445 +带口袋的健身房紧身裤
  446 +运动服
  447 +健身巾
  448 +健身房毛巾
  449 +健身房运动紧身上衣
  450 +健身房运动短裤
  451 +健身房锻炼跑步短裤
  452 +健身房运动文胸
  453 +健身房运动内衣
  454 +发巾
  455 +万圣节服装创意
  456 +露背领上衣
  457 +Halter领上衣
  458 +节省衣架空间
  459 +高跟鞋
  460 +隐藏式口袋腰包
  461 +隐藏式口袋无限围巾
  462 +隐藏式口袋护照夹背心
  463 +隐藏式口袋旅行带
  464 +隐藏口袋旅行背心
  465 +隐藏口袋女式旅行背心
  466 +高跟兼容鸡尾酒会礼服
  467 +高跟兼容连衣裙凉鞋
  468 +高跟兼容的正式连衣裙
  469 +与高跟鞋兼容的正式连身裤
  470 +与高跟鞋兼容的鞋垫
  471 +高领连衣裙
  472 +高腰紧身裤
  473 +高腰裤
  474 +高腰阔腿裤
  475 +高腰阔腿长裤
  476 +高腰牛仔牛仔裤
  477 +高腰牛仔短裤
  478 +高腰牛仔裤
  479 +登山靴
  480 +徒步旅行装备
  481 +登山裤
  482 +徒步裤女士
  483 +徒步女裤
  484 +登山衫可转换袖
  485 +徒步旅行衬衫可转换袖
  486 +旅游鞋
  487 +登山袜
  488 +徒步旅行背包
  489 +远足径雨衣
  490 +嬉皮士喇叭裤
  491 +嬉皮士扎染连衣裙
  492 +节日礼服
  493 +假日季正式礼服
  494 +节日天鹅绒连衣裙
  495 +假日天鹅绒连衣裙
  496 +返校节礼服
  497 +家居服
  498 +外套
  499 +连帽衫
  500 +千鸟皮大衣
  501 +Houndstooth大衣
  502 +instagram套装
  503 +隔热基层
  504 +保温基层
  505 +绝缘靴
  506 +绝缘手套
  507 +隔热手套
  508 +面试服装
  509 +隐形袜子
  510 +象牙色连衣裙
  511 +象牙色婚纱
  512 +夹克
  513 +牛仔裤
  514 +牛仔短裤
  515 +牛仔样式打底裤
  516 +宝石色连衣裙
  517 +珠宝色调连衣裙
  518 +宝石色调祖母绿
  519 +慢跑裤
  520 +束脚裤
  521 +连体衣
  522 +kawaii作物顶部
  523 +Kawaii作物顶部
  524 +kawaii迷你连衣裙
  525 +Kawaii迷你连衣裙
  526 +钥匙孔顶部
  527 +卡其色绿色背包
  528 +卡其色绿色帆布手提包
  529 +卡其色绿色工装裤实用
  530 +卡其色绿色军用夹克
  531 +卡其绿色防刮敞篷裤
  532 +卡其绿色耐磨面料长裤
  533 +儿童棉睡衣套装
  534 +和服
  535 +护膝
  536 +过膝长靴
  537 +针织开衫
  538 +针织帽
  539 +针织围巾
  540 +针织毛衣
  541 +针织品
  542 +蕾丝文胸
  543 +蕾丝连衣裙
  544 +灯笼袖
  545 +灯笼袖上衣
  546 +笔记本电脑背包
  547 +笔记本电脑包
  548 +分层连帽衫
  549 +皮革包
  550 +皮包
  551 +皮夹克
  552 +皮凉鞋
  553 +皮鞋
  554 +皮裙
  555 +紧身裤
  556 +豹纹衬衫
  557 +薄夹克衫
  558 +轻便夹克
  559 +轻便围巾
  560 +亚麻混纺长裙
  561 +亚麻混纺长裤
  562 +亚麻连衣裙
  563 +亚麻织物透气
  564 +亚麻裤
  565 +亚麻短裤
  566 +亚麻短套装
  567 +夏季亚麻短裤
  568 +亚麻短裤夏季
  569 +亚麻裤
  570 +猫砂盆
  571 +乐福鞋
  572 +长款运动夹克
  573 +长大衣
  574 +长袖上衣
  575 +长款束腰上衣
  576 +宽松男朋友牛仔裤
  577 +宽松的帽子
  578 +宽松开衫羊绒
  579 +宽松开襟羊毛衫
  580 +宽松图案连帽衫街头装
  581 +宽松图案印花t恤
  582 +宽松图案t恤
  583 +宽松针织毛衣
  584 +宽松夏季纯棉t恤
  585 +宽松束腰外衣
  586 +休闲服连体衣
  587 +休闲睡衣套装
  588 +休闲服睡衣套装
  589 +低腰比基尼下装
  590 +低腰牛仔裤
  591 +低腰短裤
  592 +孕妇休闲周五马球衫
  593 +孕妇装
  594 +哺乳文胸
  595 +孕妇枕头
  596 +孕妇枕
  597 +真丝孕妇袍
  598 +丝绸孕妇服
  599 +孕妇支撑带紧身裤
  600 +孕妇支撑紧身裤
  601 +黑色孕妇支撑紧身裤
  602 +孕妇泳装
  603 +孕妇长裤
  604 +孕妇高长裤
  605 +孕妇裤
  606 +孕妇装
  607 +孕妇阔腿牛仔牛仔裤
  608 +孕妇瑜伽裤
  609 +紫粉色开衫
  610 +长裙
  611 +超长连衣裙
  612 +超长裙
  613 +男式运动跑步短裤
  614 +男士正装衬衫
  615 +男士跑步短裤
  616 +男式西装背心
  617 +男士西装背心
  618 +美利奴羊毛基层
  619 +美利奴羊毛手套衬里
  620 +美利奴羊毛登山袜
  621 +美利奴羊毛徒步袜
  622 +美利奴羊毛滑雪袜
  623 +美利奴羊毛袜
  624 +美利奴羊毛袜徒步旅行
  625 +美利奴羊毛保暖基层顶层
  626 +美利奴羊毛保暖紧身裤底层
  627 +美利奴羊毛保暖内衣
  628 +网眼运动短裤
  629 +网眼运动T恤
  630 +网眼衬衫
  631 +网眼鞋
  632 +金属紧身裤
  633 +超细纤维长袍
  634 +超细纤维毛巾快干
  635 +midi鸡尾酒会连衣裙
  636 +Midi鸡尾酒会礼服
  637 +中长裙
  638 +中腰短靴牛仔裤
  639 +中号开襟牛仔裤
  640 +中腰裙
  641 +中季防水外套
  642 +军用野战夹克
  643 +军绿色夹克
  644 +军用夹克
  645 +迷你裙
  646 +极简主义的高腰裤
  647 +极简主义高帮长裤
  648 +极简主义亚麻连衣裙
  649 +极简主义亚麻长裤
  650 +极简主义钱包
  651 +迷你裙
  652 +立领衬衫
  653 +适中的长袖上衣
  654 +朴素的连体泳衣
  655 +一件式泳衣
  656 +吸湿排汗的自行车运动衫
  657 +吸湿高尔夫衬衫
  658 +男式吸湿高尔夫衬衫
  659 +吸湿运动毛巾
  660 +吸湿排汗徒步旅行t恤
  661 +妈妈装
  662 +单色服装
  663 +母亲新娘礼服
  664 +母亲节礼物
  665 +摩托车夹克
  666 +芥末黄色上衣
  667 +芥末黄上衣
  668 +航海豌豆大衣
  669 +航海泥炭大衣
  670 +航海条纹毛衣
  671 +海军蓝上衣
  672 +海军运动夹克
  673 +海军蓝羊绒无檐便帽
  674 +海军蓝羊绒毯
  675 +海军蓝羊绒混纺围巾
  676 +海军蓝羊绒围巾
  677 +海军蓝羊绒冬季大衣
  678 +霓虹粉色露脐上衣
  679 +中性色调米色
  680 +中性色调服装
  681 +新妈妈的衣服
  682 +除夕夜礼服
  683 +隐形袜
  684 +无显示袜子
  685 +凹口翻领上衣
  686 +凹口翻领运动夹克
  687 +护士擦洗
  688 +哺乳胸罩
  689 +护理服
  690 +尼龙雨衣防水
  691 +尼龙跑步短裤
  692 +尼龙短裤
  693 +气味控制运动头带
  694 +气味控制运动袜
  695 +气味控制男式运动袜
  696 +气味控制跑鞋鞋垫
  697 +气味控制鞋喷雾
  698 +气味控制垃圾桶
  699 +办公室服装
  700 +办公室穿铅笔裙
  701 +办公室穿紧身连衣裙
  702 +露肩连衣裙
  703 +露肩上衣
  704 +米白色运动鞋
  705 +橄榄绿夹克
  706 +橄榄色夹克
  707 +橄榄色多功能夹克
  708 +橄榄色夹克
  709 +连体式泳衣
  710 +单肩上衣
  711 +有机棉婴儿毯
  712 +有机棉婴儿服
  713 +有机棉圆领T恤
  714 +有机棉圆领复古T恤
  715 +有机棉圆领t恤
  716 +有机棉t恤
  717 +有机棉内衣
  718 +有机棉毛巾
  719 +有机棉白色t恤
  720 +透明硬纱上衣
  721 +超大开衫
  722 +超大连帽衫
  723 +超大针织毛衣
  724 +超大羽绒背心
  725 +超大套头衫连帽衫
  726 +超大围巾
  727 +超大t恤
  728 +超大T恤
  729 +超大高领毛衣
  730 +超大拉链连帽衫
  731 +佩斯利花纹
  732 +佩斯利印花波西米亚风格
  733 +睡衣
  734 +睡衣套装
  735 +阔腿裤
  736 +裤子
  737 +亲子配套服装
  738 +派对礼服
  739 +淡紫色毛衣
  740 +图案连身衣
  741 +图案围巾
  742 +双排扣大衣
  743 +翻领正装
  744 +铅笔裙
  745 +铅笔裙弹力
  746 +宠物照相机
  747 +小圆领
  748 +娇小的a字裙
  749 +娇小A字裙
  750 +小脚靴
  751 +小脚踝靴
  752 +小脚牛仔裤
  753 +娇小的夏装
  754 +娇小的夏季亚麻短裤
  755 +小巧的定制商务套装
  756 +小巧的定制西装外套
  757 +修身长裤,不起皱
  758 +娇小的婚礼宾客中长裙
  759 +摄影服装
  760 +粉红色毛衣
  761 +粉红色毛衣美学
  762 +格子裤
  763 +格子裙
  764 +格子长裤
  765 +厚底靴
  766 +厚底运动鞋
  767 +玩衣服
  768 +打褶网球裙
  769 +褶皱网球裙
  770 +加大码衬衫
  771 +加大码牛仔牛仔裤
  772 +加大码小牛仔裤
  773 +加大号泳装
  774 +加大码泳装
  775 +加大码束腰上衣
  776 +加大码束腰外衣上衣搭配紧身裤
  777 +加大码冬季羊毛衬里紧身裤
  778 +加大码冬季手套
  779 +加大码冬季登山靴
  780 +加大码冬季大衣
  781 +加大码女装
  782 +偏光太阳镜
  783 +圆点花纹服
  784 +Polo衫
  785 +涤纶羊毛夹克
  786 +涤纶跑步短裤
  787 +涤纶短裤
  788 +产后装
  789 +孕期枕头
  790 +学院派格子裙
  791 +Preppy格子裙
  792 +预科生格子网裙
  793 +预科生毛衣背心
  794 +Preppy毛衣背心
  795 +舞会礼服
  796 +羽绒服
  797 +羽绒背心
  798 +蓬松袖衬衫
  799 +泡泡袖衬衫
  800 +蓬松袖连衣裙
  801 +泡泡袖连衣裙
  802 +连帽卫衣
  803 +朋克仿皮裙
  804 +朋克假皮革裙
  805 +朋克风格的腰带
  806 +朋克钉带
  807 +纯棉t恤
  808 +纯棉T恤
  809 +纯亚麻浴巾
  810 +纯亚麻短套装
  811 +纯亚麻短套装海滩度假
  812 +纯亚麻夏装长裙
  813 +纯亚麻桌布
  814 +纯亚麻阔腿裤
  815 +快干衬衫
  816 +快干毛巾
  817 +绗缝夹克
  818 +棉服
  819 +雨靴
  820 +雨衣
  821 +防雨夹克
  822 +雨季风衣
  823 +雨季Anorak夹克
  824 +雨季防水靴
  825 +人造丝上衣
  826 +人造丝衬衫印花
  827 +人造丝连身衣
  828 +夏季人造丝连身裤
  829 +夏季人造丝连体衣
  830 +再生纤维连帽衫
  831 +再生纤维运动鞋
  832 +再生聚酯袋
  833 +再生聚酯健身袋
  834 +再生聚酯笔记本电脑套
  835 +再生聚酯可重复使用购物袋
  836 +再生聚酯跑步夹克
  837 +再生聚酯游泳短裤
  838 +再生聚酯防水外套
  839 +红色丝绸衬衫
  840 +宽松的牛仔夹克
  841 +宽松的牛仔短裤
  842 +宽松版型牛仔短裤
  843 +宽松版型毛衣
  844 +宽松运动裤
  845 +宽松版型运动裤
  846 +度假服装
  847 +复古喇叭牛仔裤
  848 +复古喇叭裤
  849 +复古图案连身裤
  850 +肋状罐顶
  851 +罗纹背心
  852 +马靴
  853 +防撕裂工装裤
  854 +长袍
  855 +浪漫雪纺衬衫
  856 +浪漫的泡泡袖上衣
  857 +浪漫的丝绸衬衫
  858 +浪漫丝绸衬衫
  859 +连体衣
  860 +玫瑰金首饰
  861 +圆形太阳镜
  862 +皱边裙
  863 +泡泡袖
  864 +褶边袖上衣
  865 +运动夹克
  866 +跑步夹克
  867 +跑步紧身裤
  868 +运动短裤
  869 +带衬里的运动短裤
  870 +带衬里的跑步短裤
  871 +铁锈色毛衣
  872 +锈色中裙
  873 +锈米裙
  874 +鼠尾草绿色休息室套装
  875 +Sage绿色休息室套装
  876 +凉鞋
  877 +缎面卡米上衣
  878 +缎面背心
  879 +缎面长袍
  880 +围巾
  881 +香薰蜡烛
  882 +校服
  883 +校服上衣
  884 +校服运动夹克
  885 +校服马球衫
  886 +校服Polo衫
  887 +勺颈油箱
  888 +大圆领背心
  889 +发圈
  890 +无缝瑜伽紧身裤
  891 +半正式晚礼服
  892 +亮片鸡尾酒会连衣裙
  893 +亮片鸡尾酒会礼服
  894 +剃须刀
  895 +青果领开衫
  896 +紧身连衣裙
  897 +透明硬纱上衣
  898 +短外套
  899 +夏尔巴夹克
  900 +夏尔巴人夹克
  901 +闪闪发光的金属露脐上衣
  902 +闪闪发光的金属紧身裤
  903 +闪闪发光的金属紧身裤瑜伽
  904 +闪闪发光的金属色派对裙
  905 +闪闪发光的金属手机壳
  906 +衬衫
  907 +鞋嵌件
  908 +鞋套
  909 +鞋带
  910 +短裤
  911 +短集
  912 +丝绸衬衫
  913 +丝绸连衣裙
  914 +丝绸睡衣
  915 +真丝睡衣
  916 +丝绸睡衣套装
  917 +丝绸长袍
  918 +丝绸吊带裙
  919 +银色金属高跟鞋
  920 +滑雪羊毛中层
  921 +滑雪保暖内衣
  922 +滑雪旅行保温基层
  923 +紧身牛仔裤
  924 +紧身裤
  925 +紧身长裤
  926 +紧身牛仔裤
  927 +紧身裤
  928 +滑雪用具
  929 +裙子
  930 +裙装
  931 +滑雪袜
  932 +滑雪短袜
  933 +无袖连衣裙
  934 +无袖夏装
  935 +修身及踝长裤
  936 +修身脚踝长裤
  937 +修身运动夹克羊毛
  938 +修身运动衫羊毛
  939 +修身纽扣衬衫
  940 +修身长裤
  941 +吊带裙
  942 +穿上运动鞋
  943 +防滑运动鞋
  944 +时髦休闲男士
  945 +蛇纹靴
  946 +运动鞋搭配脚踝袜
  947 +运动鞋搭配工装裤
  948 +运动鞋搭配隐形袜子
  949 +运动鞋搭配低帮袜子
  950 +运动鞋搭配未露面的袜子
  951 +运动鞋配套鞋带
  952 +运动鞋
  953 +袜子靴
  954 +沙发床
  955 +柔软的长袍
  956 +意大利面条表带卡米
  957 +意大利面条吊带背心
  958 +细肩带连衣裙
  959 +氨纶压缩文胸
  960 +氨纶自行车短裤
  961 +氨纶骑行短裤
  962 +运动文胸
  963 +运动文胸高冲击力
  964 +运动内衣高冲击力
  965 +运动上衣
  966 +运动装
  967 +春季花衬衫
  968 +春季花朵衬衫
  969 +春季轻质花夹克
  970 +春季风衣少女
  971 +春季风衣
  972 +方领上衣
  973 +防污围裙烹饪
  974 +防污男孩运动裤
  975 +防污儿童游戏服
  976 +防污儿童校服
  977 +防污餐垫
  978 +防污白色t恤
  979 +细高跟靴
  980 +细高跟鞋
  981 +细高跟鞋护具
  982 +直筒裤
  983 +直筒及踝长裤办公服
  984 +直筒及踝弹力裤
  985 +直筒防擦伤裤
  986 +直筒牛仔裤
  987 +直筒裤
  988 +直筒裤工作
  989 +直筒裤工作服
  990 +无肩带连衣裙
  991 +草帽
  992 +街头服饰图案连帽衫
  993 +街头风衣男子连帽衫
  994 +街头装连帽衫男式
  995 +街头装超大连帽衫
  996 +街头装拉链连帽衫
  997 +弹力牛仔裤
  998 +直筒弹力牛仔裤
  999 +弹力牛仔裤直筒
  1000 +条纹衬衫
  1001 +深蓝色条纹衬衫
  1002 +条纹衬衫海军蓝
  1003 +条纹毛衣
  1004 +镶钉皮带
  1005 +绒面短靴
  1006 +绒面脚踝靴
  1007 +绒面靴
  1008 +绒面乐福鞋
  1009 +绒面休闲乐福鞋
  1010 +绒面乐福鞋休闲
  1011 +套装
  1012 +西装外套
  1013 +西装男
  1014 +男士西装
  1015 +夏季快干UPF 50衬衫
  1016 +夏季无肩带连衣裙
  1017 +夏季太阳花连衣裙
  1018 +夏季连衣裙花朵
  1019 +太阳裙
  1020 +遮阳帽
  1021 +宽边太阳帽
  1022 +防晒服
  1023 +支撑带
  1024 +毛衣
  1025 +毛衣连衣裙
  1026 +毛衣背心
  1027 +运动裤
  1028 +运动衫
  1029 +运动服
  1030 +甜心领口连衣裙
  1031 +泳装
  1032 +游泳短裤
  1033 +泳衣
  1034 +泳裤
  1035 +定制衬衫
  1036 +女式西服
  1037 +定制西装夹克
  1038 +定制西装修身
  1039 +定制修身西装
  1040 +高挑修身商务休闲夹克
  1041 +高挑修身男式衬衫
  1042 +高挑修身男式亚麻衬衫
  1043 +高挑修身男式西装背心
  1044 +高挑修身西装上衣
  1045 +高挑修身领带
  1046 +高挑修身长裤
  1047 +高腰修身长裤
  1048 +高直筒裤
  1049 +背心
  1050 +流苏长裙
  1051 +教师服装
  1052 +青色衬衫
  1053 +青色缎面衬衫
  1054 +温度调节床垫
  1055 +调温睡衣
  1056 +调温枕
  1057 +调温丝绸睡衣
  1058 +调温睡衣
  1059 +调温冬袜
  1060 +网球裙
  1061 +赤土亚麻长裤
  1062 +赤陶亚麻长裤
  1063 +赤土裤
  1064 +毛圈布浴袍
  1065 +毛巾布浴袍
  1066 +毛圈布短裤
  1067 +毛圈布运动衫
  1068 +Terry布运动衫
  1069 +热基层
  1070 +热基层顶部
  1071 +保暖长袖上衣
  1072 +保暖滑雪夹克
  1073 +保暖内衣
  1074 +防擦伤大腿短裤
  1075 +大腿短裤防擦伤
  1076 +系
  1077 +领带
  1078 +扎染桶帽
  1079 +扎染连衣裙
  1080 +扎染超大针织毛衣
  1081 +扎染大号运动衫
  1082 +扎染超大运动衫
  1083 +扎染袜子颜色柔和
  1084 +扎染夏季长裙
  1085 +扎染水瓶
  1086 +扎腰裤
  1087 +系带长裤
  1088 +tiktok服装
  1089 +幼儿床
  1090 +托特包
  1091 +运动服
  1092 +运动服快干
  1093 +过渡轻便夹克
  1094 +过渡性毛衣背心
  1095 +过渡款毛衣背心
  1096 +旅行服装
  1097 +旅行夹克
  1098 +轻便旅行夹克
  1099 +旅行服装
  1100 +旅行轻便围巾
  1101 +旅行裤
  1102 +旅行套装
  1103 +旅行背心
  1104 +旅行防皱裤
  1105 +旅行无皱纹长裤
  1106 +风衣
  1107 +热带气候透气短裤
  1108 +热带气候凉鞋
  1109 +热带气候凉鞋皮革
  1110 +热带印花衬衫
  1111 +裤子
  1112 +喇叭袖
  1113 +喇叭袖上衣
  1114 +小号袖上衣
  1115 +T恤
  1116 +抹胸上衣
  1117 +薄纱覆面裙
  1118 +薄纱裙
  1119 +薄纱裙派对
  1120 +束腰外衣
  1121 +束腰上衣
  1122 +宽松上衣
  1123 +束腰上衣宽松版型
  1124 +高领毛衣
  1125 +粗花呢西装外套
  1126 +两件套
  1127 +难看的圣诞毛衣
  1128 +伞
  1129 +内衣
  1130 +多功能工装裤
  1131 +通用工装裤
  1132 +实用货物裙
  1133 +多功能货物裙
  1134 +紫外线防护口罩
  1135 +防紫外线钓鱼衫
  1136 +防紫外线园艺帽
  1137 +防紫外线太阳帽
  1138 +防紫外线女式防晒手套
  1139 +度假服装
  1140 +情人节服装
  1141 +天鹅绒鸡尾酒会礼服
  1142 +天鹅绒连衣裙
  1143 +天鹅绒高跟鞋
  1144 +天鹅绒高跟鞋正式
  1145 +天鹅绒高跟正式
  1146 +天鹅绒节日连衣裙
  1147 +天鹅绒中长裙
  1148 +丝绒迷笛裙
  1149 +天鹅绒裙子
  1150 +背心
  1151 +复古牛仔夹克
  1152 +复古旧牛仔夹克
  1153 +复古皮裙
  1154 +粘胶卡米上衣
  1155 +粘胶纤维背心
  1156 +粘胶围巾图案
  1157 +V领T恤
  1158 +华夫饼针织亨利
  1159 +华夫格针织亨利
  1160 +束腰
  1161 +钱包
  1162 +防水靴
  1163 +防水连帽夹克
  1164 +防水雨衣
  1165 +防水外壳
  1166 +防水外壳外套
  1167 +防水喷雾
  1168 +穿着小衣服
  1169 +婚礼宾客鸡尾酒会礼服
  1170 +婚礼宾客礼服
  1171 +婚礼宾客正装
  1172 +婚礼宾客中长裙
  1173 +婚礼宾客迷笛裙
  1174 +婚礼宾客吊带裙
  1175 +西部牛仔靴
  1176 +西式牛仔衬衫
  1177 +白色棉质t恤
  1178 +白色亚麻长裤
  1179 +宽边帽
  1180 +售宽裤筒牛仔裤
  1181 +阔腿亚麻裤
  1182 +宽腿亚麻长裤
  1183 +阔腿宫殿长裤
  1184 +阔腿Palazzo长裤
  1185 +阔腿裤
  1186 +窗膜
  1187 +冬季羊毛衬里紧身裤
  1188 +冬季手套
  1189 +冬季服装
  1190 +冬季派克大衣
  1191 +冬季公园
  1192 +冬季大衣羽绒服
  1193 +冬季帕卡羽绒服
  1194 +冬季羽绒服
  1195 +女式夏季长裙
  1196 +羊毛外套
  1197 +羊毛混纺长外套
  1198 +羊毛大衣
  1199 +羊毛大衣高
  1200 +羊毛豌豆大衣
  1201 +羊毛袜
  1202 +羊毛冬衣
  1203 +羊毛冬季大衣
  1204 +居家办公
  1205 +运动服
  1206 +工作裤
  1207 +工作服长裤
  1208 +裹身裙
  1209 +抗皱商务衬衫
  1210 +抗皱商务旅行套装
  1211 +抗皱织物喷雾
  1212 +抗皱长裤
  1213 +抗皱旅行夹克
  1214 +抗皱旅行裙
  1215 +抗皱旅行裤
  1216 +抗皱喷雾
  1217 +y2k低腰宽松牛仔裤
  1218 +y2k低腰工装裤
  1219 +y2k低腰牛仔裤
  1220 +Y2K低腰牛仔裤
  1221 +y2k管顶
  1222 +Y2K管顶
  1223 +瑜伽紧身裤
  1224 +瑜伽垫
  1225 +瑜伽服
  1226 +瑜伽裤
  1227 +高腰瑜伽裤
  1228 +瑜伽短裤
  1229 +斑马印花长裤
  1230 +拉链靴
  1231 +拉链连帽衫
  1232 +变焦衬衫
... ...
tests/queries.txt renamed to scripts/evaluation/queries/queries.txt
前端分面配置说明.md deleted
... ... @@ -1,176 +0,0 @@
1   -# 前端分面配置说明
2   -
3   -## 问题描述
4   -
5   -tenant_id=170 的分面返回为空,原因是:
6   -1. `category1_name` 字段在数据中为 None(这是数据问题)
7   -2. `specifications.name` 字段在数据中使用首字母大写(如 "Color"、"Size"),而前端查询时使用小写("color"、"size"),导致 ES term 查询匹配失败
8   -
9   -## 解决方案
10   -
11   -采用前端配置方案,根据不同的 `tenant_id` 配置不同的分面字段。配置包括:
12   -- **字段名**(field):ES 中的实际字段名,如 `specifications.Color`
13   -- **显示标签**(label):前端显示的名称,如 "颜色"、"尺寸"
14   -- **容器ID**(containerId):HTML 中用于显示分面的容器 ID,如 `colorTags`
15   -- **查询参数**:size、type、disjunctive 等
16   -
17   -## 配置文件
18   -
19   -配置文件位置:`frontend/static/js/tenant_facets_config.js`
20   -
21   -### 配置结构
22   -
23   -```javascript
24   -const TENANT_FACETS_CONFIG = {
25   - "租户ID": {
26   - specificationFields: [
27   - {
28   - field: "specifications.字段名", // ES字段名(必须与实际数据匹配,包括大小写)
29   - label: "显示标签", // 前端显示名称
30   - containerId: "容器ID", // HTML容器ID
31   - size: 20, // 返回的分面值数量
32   - type: "terms", // 分面类型
33   - disjunctive: true // 是否支持多选
34   - }
35   - ]
36   - }
37   -};
38   -```
39   -
40   -### 示例配置
41   -
42   -#### tenant_id=162(使用小写)
43   -```javascript
44   -"162": {
45   - specificationFields: [
46   - {
47   - field: "specifications.color",
48   - label: "Color",
49   - containerId: "colorTags",
50   - size: 20,
51   - type: "terms",
52   - disjunctive: true
53   - },
54   - {
55   - field: "specifications.size",
56   - label: "Size",
57   - containerId: "sizeTags",
58   - size: 15,
59   - type: "terms",
60   - disjunctive: true
61   - },
62   - {
63   - field: "specifications.material",
64   - label: "Material",
65   - containerId: "materialTags",
66   - size: 10,
67   - type: "terms",
68   - disjunctive: true
69   - }
70   - ]
71   -}
72   -```
73   -
74   -#### tenant_id=170(使用首字母大写,没有material)
75   -```javascript
76   -"170": {
77   - specificationFields: [
78   - {
79   - field: "specifications.Color", // 注意:首字母大写
80   - label: "Color",
81   - containerId: "colorTags",
82   - size: 20,
83   - type: "terms",
84   - disjunctive: true
85   - },
86   - {
87   - field: "specifications.Size", // 注意:首字母大写
88   - label: "Size",
89   - containerId: "sizeTags",
90   - size: 15,
91   - type: "terms",
92   - disjunctive: true
93   - }
94   - // 注意:170 没有 material 分面
95   - ]
96   -}
97   -```
98   -
99   -#### 示例:添加新租户(包含其他规格字段,如重量、包装方式)
100   -```javascript
101   -"新租户ID": {
102   - specificationFields: [
103   - {
104   - field: "specifications.Weight", // 重量
105   - label: "Weight",
106   - containerId: "weightTags", // 需要在HTML中添加此容器
107   - size: 15,
108   - type: "terms",
109   - disjunctive: true
110   - },
111   - {
112   - field: "specifications.PackageType", // 包装方式
113   - label: "Package Type",
114   - containerId: "packageTags", // 需要在HTML中添加此容器
115   - size: 10,
116   - type: "terms",
117   - disjunctive: true
118   - }
119   - ]
120   -}
121   -```
122   -
123   -## 添加新租户配置步骤
124   -
125   -1. **确定 ES 数据中的实际字段名**
126   - - 检查 ES 中 `specifications.name` 的实际值(注意大小写)
127   - - 例如:`"Color"` 或 `"color"` 是不同的字段
128   -
129   -2. **在配置文件中添加配置**
130   - ```javascript
131   - "新租户ID": {
132   - specificationFields: [
133   - {
134   - field: "specifications.实际字段名",
135   - label: "显示名称",
136   - containerId: "容器ID",
137   - size: 20,
138   - type: "terms",
139   - disjunctive: true
140   - }
141   - ]
142   - }
143   - ```
144   -
145   -3. **在 HTML 中添加容器**(如果需要新的容器)
146   - 在 `frontend/index.html` 的 Filter Section 中添加:
147   - ```html
148   - <div class="filter-row">
149   - <div class="filter-label">显示名称:</div>
150   - <div class="filter-tags" id="容器ID"></div>
151   - </div>
152   - ```
153   -
154   -## 代码修改说明
155   -
156   -### 1. 配置文件 (`tenant_facets_config.js`)
157   -- 增加了 `label` 和 `containerId` 字段
158   -- 新增 `getFacetDisplayConfig()` 函数,根据字段名获取显示配置
159   -
160   -### 2. 前端代码 (`app.js`)
161   -- `performSearch()`: 使用配置文件获取分面查询参数
162   -- `displayFacets()`: 使用配置来匹配分面字段并找到对应的容器
163   -
164   -### 3. HTML (`index.html`)
165   -- 引入了配置文件 `tenant_facets_config.js`
166   -
167   -## 注意事项
168   -
169   -1. **字段名必须完全匹配**:`field` 必须与 ES 中实际存储的 `specifications.name` 值完全匹配(包括大小写)
170   -2. **容器ID必须存在**:`containerId` 必须在 HTML 中存在,否则分面无法显示
171   -3. **后端代码无需修改**:后端直接使用前端传入的字段名进行查询
172   -4. **分面信息是动态加载的**:只有在搜索返回后才显示,符合需求
173   -
174   -## 数据问题说明
175   -
176   -对于 tenant_id=170,`category1_name` 字段在 ES 数据中全部为 None,因此该类目分面会返回空。这需要在数据索引时修复,确保正确解析和填充 `category1_name` 字段。