天猫返利app搜索系统优化:基于Elasticsearch的商品导购引擎设计
大家好,我是省赚客APP研发者阿可!在省赚客APP(juwatech.cn)中,用户通过关键词快速查找高返利天猫商品是核心场景。面对亿级商品数据、毫秒级响应要求及复杂排序策略(如"高佣金+高销量+低价格"),我们基于 Elasticsearch 构建了高性能商品导购引擎。本文将从索引设计、查询构建、相关性调优到工程集成,结合实际代码详解关键实现。
商品索引结构设计:多字段与嵌套属性支持
我们为商品建立 tmall_products 索引,兼顾全文检索、精确过滤与聚合分析:
json
PUT /tmall_products
{
"settings": {
"number_of_shards": 6,
"number_of_replicas": 1,
"analysis": {
"analyzer": {
"ik_max_word_pinyin": {
"tokenizer": "ik_max_word",
"filter": ["pinyin_filter"]
}
},
"filter": {
"pinyin_filter": {
"type": "pinyin",
"keep_full_pinyin": true,
"keep_original": true
}
}
}
},
"mappings": {
"properties": {
"itemId": { "type": "keyword" },
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": {
"pinyin": { "type": "text", "analyzer": "ik_max_word_pinyin" }
}
},
"categoryId": { "type": "keyword" },
"brandId": { "type": "keyword" },
"price": { "type": "scaled_float", "scaling_factor": 100 },
"salesCount": { "type": "integer" },
"commissionRate": { "type": "scaled_float", "scaling_factor": 10000 },
"rebateAmount": { "type": "scaled_float", "scaling_factor": 100 },
"tags": { "type": "keyword" },
"specs": {
"type": "nested",
"properties": {
"key": { "type": "keyword" },
"value": { "type": "keyword" }
}
},
"status": { "type": "byte" }
}
}
}

Java实体与Repository封装
使用 Spring Data Elasticsearch 定义文档模型:
java
package juwatech.cn.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;
@Document(indexName = "tmall_products")
public class TmallProductDoc {
@Id
private String itemId;
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String title;
@Field(type = FieldType.Keyword)
private String categoryId;
@Field(type = FieldType.Scaled_Float, scalingFactor = 100)
private BigDecimal price;
@Field(type = FieldType.Integer)
private Integer salesCount;
@Field(type = FieldType.Scaled_Float, scalingFactor = 10000)
private BigDecimal commissionRate;
@Field(type = FieldType.Nested)
private List<Spec> specs;
// getters/setters
}
多条件组合查询构建
通过 BoolQueryBuilder 实现关键词、类目、价格区间、规格等混合筛选:
java
package juwatech.cn.service;
@Service
public class ProductSearchService {
@Autowired
private ElasticsearchRestTemplate elasticsearchTemplate;
public SearchPage<TmallProductDoc> search(SearchRequest req) {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
// 1. 全文检索(支持中文+拼音)
if (StringUtils.isNotBlank(req.getKeyword())) {
BoolQueryBuilder textQuery = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("title", req.getKeyword()))
.should(QueryBuilders.matchQuery("title.pinyin", req.getKeyword()));
builder.withQuery(textQuery);
}
// 2. 类目过滤
if (req.getCategoryId() != null) {
builder.withFilter(QueryBuilders.termQuery("categoryId", req.getCategoryId()));
}
// 3. 价格区间
if (req.getMinPrice() != null || req.getMaxPrice() != null) {
RangeQueryBuilder priceRange = QueryBuilders.rangeQuery("price");
if (req.getMinPrice() != null) priceRange.gte(req.getMinPrice());
if (req.getMaxPrice() != null) priceRange.lte(req.getMaxPrice());
builder.withFilter(priceRange);
}
// 4. 规格筛选(Nested Query)
if (req.getSpecFilters() != null) {
for (Map.Entry<String, String> spec : req.getSpecFilters().entrySet()) {
NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("specs",
QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery("specs.key", spec.getKey()))
.must(QueryBuilders.termQuery("specs.value", spec.getValue())),
ScoreMode.None);
builder.withFilter(nestedQuery);
}
}
// 5. 排序策略
builder.withSort(SortBuilders.scriptSort(
new Script(
ScriptType.INLINE,
"painless",
"doc['rebateAmount'].value * 0.6 + doc['salesCount'].value / 10000.0 * 0.4",
Collections.emptyMap()
),
ScriptSortType.NUMBER
).order(SortOrder.DESC));
builder.withPageable(PageRequest.of(req.getPage(), req.getSize()));
return elasticsearchTemplate.search(builder.build(), TmallProductDoc.class);
}
}
相关性评分定制:业务加权融合
默认 TF-IDF 不符合导购场景,我们通过 function_score 融合文本匹配与业务指标:
java
FunctionScoreQueryBuilder functionScore = QueryBuilders.functionScoreQuery(
textQuery, // 基础查询
new FunctionScoreQueryBuilder.FilterFunctionBuilder[] {
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
ScoreFunctionBuilders.fieldValueFactorFunction("rebateAmount").factor(1.0f)
),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(
ScoreFunctionBuilders.fieldValueFactorFunction("salesCount").factor(0.0001f)
)
}
).boostMode(CombineFunction.MULTIPLY);
builder.withQuery(functionScore);
数据同步机制:近实时更新
商品数据变更通过 Canal 监听 MySQL Binlog,经 Kafka 异步写入 ES:
java
@KafkaListener(topics = "tmall_product_update")
public void handleProductUpdate(ConsumerRecord<String, String> record) {
TmallProduct product = JsonUtil.fromJson(record.value(), TmallProduct.class);
TmallProductDoc doc = convertToDoc(product);
elasticsearchTemplate.save(doc);
}
下架商品立即删除:
java
if (product.getStatus() == 0) {
elasticsearchTemplate.delete(doc.getItemId(), TmallProductDoc.class);
}
本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!