Java生鮮電商平台-搜索模塊的設計與架構
說明:搜索模塊針對的是買家用戶,在找菜品找的很費勁下的一種查詢方面。目前也是快速的檢索商品。
對於移動端的APP買家用戶而言,要求的速度在3秒內完成。支持模糊查詢,由於業務實戰表面,整個搜索頻率不到18%-25%之間
同時業務也不算很大,所以並沒采用java全文檢索技術.(lucene等)。這里采用的就是基本的模糊查詢。
1. 搜索維度的是思考。
1.1 買家搜索的內容很有可能是針對菜品的本身屬性而言,所以涉及到的內容有商品名稱,商品別名,商品標簽,商品描述,規格的名稱,加工方式等。
1.2 我們知道模糊搜索會導致索引失效,同時整個查詢性能也是有影響的。
1.3 業務形態顯示有些熱點的詞語與內容可以做JVM緩存以提高整個單品的購買率。比如土豆現在分析出很多人要,如果我們可以跟某個商家談好,一天
需要10w斤土豆的量進行供應,那么整個頁面會出現這個關鍵字的默認顯示。這個是后端靈活配置的。
2. 對於買家搜索的關鍵字,我們需要數據庫進行記錄,這樣可以從系統級別算出買家會需要什么,可以進行針對性的營銷.
相關數據庫表的設計如下:
CREATE TABLE `buyer_search` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動增加ID', `buyer_id` bigint(20) DEFAULT NULL COMMENT '買家ID', `words` bigint(20) DEFAULT NULL COMMENT '賣家ID', `create_time` datetime DEFAULT NULL COMMENT '創建時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='買家搜索記錄表';
補充說明:目的其實是很明確的,就是記錄買家搜索的關鍵字以便分析與研究用。為了更好的體驗用戶。
相關業務代碼如下:
/**
* APP全文搜索 新
* @param request
* @param response
* @param keyword
* @return
*/
@RequestMapping(value = "/search/new", method = { RequestMethod.GET, RequestMethod.POST })
public JsonResult newSearchGoods(HttpServletRequest request, HttpServletResponse response,Long userId,Long regionId,String keyword){
try{
logger.info("SearchController.search.keyword:搜索內容:" + keyword);
//搜索結果按商家顯示
//List<SellerVo> list = sellerService.searchSeller(regionId,keyword);
//搜索結果按商品顯示
List<NewSearchVo> list = goodsService.newSearchGoods(userId,regionId,keyword);
return new JsonResult(JsonResultCode.SUCCESS, "查詢信息成功", list);
}catch(Exception ex){
logger.error("[SearchController][newSearchGoods] exception :",ex);
return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍后重試","");
}
}
VO對象如下:
/**
* 搜索顯示類(APP全局搜索)
*/
public class NewSearchVo implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 來源於users的ID
*/
private Long sellerId;
/**
* 店鋪名稱
*/
private String sellerName;
/**
* 店鋪別名,可以理解為簡稱
*/
private String sellerAlias;
/**
* 店鋪logo
*/
private String sellerLogo;
/**
* 店鋪評級,默認為0
*/
private int sellerRank;
/**
* 店鋪評分
*/
private Double sellerGrade;
/**
* 搜索后商品列表
*/
private List<GoodsVo> searchItemList;
public Long getSellerId() {
return sellerId;
}
public void setSellerId(Long sellerId) {
this.sellerId = sellerId;
}
public String getSellerName() {
return sellerName;
}
public void setSellerName(String sellerName) {
this.sellerName = sellerName;
}
public String getSellerAlias() {
return sellerAlias;
}
public void setSellerAlias(String sellerAlias) {
this.sellerAlias = sellerAlias;
}
public String getSellerLogo() {
return sellerLogo;
}
public void setSellerLogo(String sellerLogo) {
this.sellerLogo = sellerLogo;
}
public int getSellerRank() {
return sellerRank;
}
public void setSellerRank(int sellerRank) {
this.sellerRank = sellerRank;
}
public Double getSellerGrade() {
return sellerGrade;
}
public void setSellerGrade(Double sellerGrade) {
this.sellerGrade = sellerGrade;
}
public List<GoodsVo> getSearchItemList() {
return searchItemList;
}
public void setSearchItemList(List<GoodsVo> searchItemList) {
this.searchItemList = searchItemList;
}
}
3, 數據查詢性能暫時的基本滿足要求,也貼出來給大家一起參考,目的是共同學習與思考.
<!-- 全局搜索商品 新-->
<select id="newSearchGoods" resultMap="newSearchResult">
<include refid="newSearchSelect" />
<include refid="newSearchFrom" />
<include refid="searchWhere" />
<if test=" keyword != null">
and (g.goods_name like concat('%',#{keyword},'%')
or g.goods_as like concat('%',#{keyword},'%')
or g.goods_label like concat('%',#{keyword},'%')
or g.goods_brand like concat('%',#{keyword},'%')
or g.goods_desc like concat('%',#{keyword},'%')
or gf.format_name like concat('%',#{keyword},'%')
or pm.method_name like concat('%',#{keyword},'%')
or s.seller_name like concat('%',#{keyword},'%')
or exists(select 1 from category where category_id = g.category_id and category_name like concat('%',#{keyword},'%') )
)
</if>
<include refid="searchOrderBy" />
</select>
總結,由於搜索這塊所涉及的業務相對而言比較少,功能也比較單一,含金量不是很高,所以互相學習。
對於擴展方案,如果這塊的業務發現很大,可以采用中文分詞記錄,進行數據的挖掘,已經冷熱點數據的一個分離等等,這個后期大家有需要的話,我們再研究。
相關業務運營截圖如下:



