머리말
제품 검색 모듈이 프로젝트에 참여하고 있으며, ES 지식을 습득하여 프로젝트에 ES를 적용하려고 노력하고 있습니다.이 블로그는 주로 프로젝트에서 ES를 사용하는 방법을 설명합니다. 함께 구입 한 Alibaba Cloud 서버가 만료되었으므로 여기에서는 시연하지 않습니다. 향후 작업을 위해 좋은 서버를 구입해야합니다.
ES 및 Kibana도 설치하려면 이전 블로그를 따라 포털 을 구축 할 수
있습니다. <---- 여기를 클릭하십시오.
ES의 데이터 모델
ES에서 데이터를 확인하려면 먼저 ES에 데이터를 저장해야합니다. 그때는 반 친구들과 Kibana에서 직접 데이터를 가져 오는 방법에 대해 논의했지만 생각하면 너무 힘들어요. 나중에 반 친구들이 작성한 백 스테이지 관리에 제품이 있다고 생각했습니다. 선반에있는 기능은 여기서부터 시작합니다.
모델 디자인
우리가 설계 한 모델을 살펴보십시오.
@Data
public class SkuEsModel {
//具体商品的id
private Long skuId;
//某类商品的id
private Long spuId;
//销售商品的标题
private String skuTitle;
//销售商品的价格
private BigDecimal skuPrice;
//销售商品的图片
private String skuImg;
//商品的销量
private Long saleCount;
//商品是否有库存
private Boolean hasStock;
//商品的评分
private Long hotScore;
//商品所属品牌的id
private Long brandId;
//商品所属分类的id
private Long catalogId;
//商品所属品牌的名字
private String brandName;
//商品所属品牌的图片
private String brandImg;
//商品所属分类的名字
private String catalogName;
//商品所对应的属性
private List<Attrs> attrs;
@Data
public static class Attrs {
//属性id
private Long attrId;
//属性的名字
private String attrName;
//属性值
private String attrValue;
}
}
이런 디자인을하는 이유
먼저 쇼핑몰의 비즈니스에서 es를 사용하는 것에 대해 이야기 해 보겠습니다.
- 쇼핑몰 홈페이지 3 단계 목록의 3 단계 디렉토리를 통해 검색 페이지로 진입
- 쇼핑몰 홈페이지 검색 창을 통해 검색하고자하는 상품명을 입력하고 es를 체크하여 데이터를 반환
3 단계 디렉토리를 클릭하여 입력하면 카테고리 ID 매개 변수가 전달되므로 검색을 제공 할 모델에 카테고리 ID가 있어야하며 검색 상자를 통해 입력하면 sku 제품의 제목과 일치하는 문자열 매개 변수가 전달됩니다.
따라서 이러한 검색을 통해 세부 정보 페이지에서 렌더링 할 프런트 엔드를 제공하려면 어떤 데이터가 필요합니까?
위의 스크린 샷은 JD.com에서 찍은 것입니다. 제 반 친구들은 JD의 페이지를 기반으로 일부 기능을 모방했습니다. 사진의 주석을 읽은 후 모델이 왜 그렇게 디자인되었는지 이해해야합니다. 그러나 상품 상세 페이지와 관련된 다른 필드가 있습니다. 이 검색 페이지에 대해 먼저 이야기합시다.
검색 페이지에서 중간에있는 이러한 속성 및 브랜드는 검색에 따라 서로 다른 답변을 제공해야하므로 es의 집계 연산을 통해 구현됩니다.
이제 논의 할 또 다른 주제가 있습니다.이 정보는 집계를 통해 어떻게 확보됩니까?
우선 내일 모레 관리자가 선반을 클릭하면 해당 skuId와 해당 spu가 속한 spu 정보가 표시됩니다. 선반에 있으면 데이터베이스에서 확인하고 SkuModel에서 정보를 찾아 캡슐화 한 다음 원격으로 검색 서비스를 호출합니다. 이러한 데이터는 es에 저장됩니다.
ES에 입금하는 방법
다음으로 es 인덱스 매핑의 디자인을 살펴보십시오.
PUT product
{
"mappings": {
"properties": {
"skuId": {
"type": "long"
},
"spuId": {
"type": "long"
},
"skuTitle": {
"type": "text",//支持全文搜索的
"analyzer": "ik_smart"//采用ik分词器
},
"skuPrice": {
"type": "keyword"//必须输入精确值才能搜索
},
"skuImg": {
"type": "keyword",//必须输入精确值才能搜索
"index": false,//不能被索引
"doc_values": false
},
"saleCount": {
"type": "long"
},
"hosStock": {
"type": "boolean"
},
"hotScore": {
"type": "long"
},
"brandId": {
"type": "long"
},
"catelogId": {
"type": "long"
},
"brandName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"brandImg": {
"type": "keyword",
"index": false,
"doc_values": false
},
"catelogName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"attrs": {
"type": "nested",//es的嵌套模型
"properties": {
"attrId": {
"type": "long"
},
"attrName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"attrValue": {
"type": "keyword"
}
}
}
}
}
}
ES API : RestHighLevelClient를 Java를 통해 운영하여 ES의 추가, 삭제, 수정을 수행 한 후 저장 방법 확인
@Override
public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {
//1.在es中建立索引,建立号映射关系
//2. 在ES中保存这些数据
BulkRequest bulkRequest = new BulkRequest();
for (SkuEsModel skuEsModel : skuEsModels) {
//构造保存请求
IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
indexRequest.id(skuEsModel.getSkuId().toString());
String jsonString = JSON.toJSONString(skuEsModel);
indexRequest.source(jsonString, XContentType.JSON);
bulkRequest.add(indexRequest);
}
BulkResponse bulk = esRestClient.bulk(bulkRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);
//TODO 如果批量错误
boolean hasFailures = bulk.hasFailures();
List<String> collect = Arrays.asList(bulk.getItems()).stream().map(item -> {
return item.getId();
}).collect(Collectors.toList());
log.info("商品上架完成:{}",collect);
return hasFailures;
}
ES에서 데이터를 확인하는 방법
쿼리 매개 변수, 이러한 매개 변수를 캡슐화하는 모델도 설계했습니다.
@Data
public class SearchParam {
/**
* 页面传递过来的全文匹配关键字
*/
private String keyword;
/**
* 品牌id,可以多选
*/
private List<Long> brandId;
/**
* 三级分类id
*/
private Long catalog3Id;
/**
* 排序条件:sort=price/salecount/hotscore_desc/asc
*/
private String sort;
/**
* 是否显示有货
*/
private Integer hasStock;
/**
* 价格区间查询
*/
private String skuPrice;
/**
* 按照属性进行筛选
*/
private List<String> attrs;
/**
* 页码
*/
private Integer pageNum = 1;
/**
* 原生的所有查询条件
*/
private String _queryString;
}
이러한 매개 변수를 전달한 다음 es로 이동하여 어셈블리 쿼리에 해당하는 인덱스를 찾고 쿼리 단계를 요약합니다.
- 쿼리에 필요한 DSL 문을 동적으로 구성
- 검색 요청 준비 :
1
퍼지 일치, 필터링 (속성, 분류, 브랜드, 가격 범위, 인벤토리에 따라), 정렬, 페이징, 강조 표시, 집계 분석2
, 집계 : 브랜드 집계, 분류 집계, 속성 집계 - 검색 요청 수행
- 응답 데이터를 분석하고 필요한 형식으로 캡슐화합니다.
- 반환