zoukankan      html  css  js  c++  java
  • java B2B2C多用户商城系统-搜索分词架构分享

    需求分析:

    在javashop电商系统中,商品数据是存在elasticsearch中,使用ik分词器分词,ik分词器的词库内置了2万多个。

    但在实际运维过程中,因为商品的个性化,词库不一定可以满足,为了搜索引擎分词(关键词)更加准确,要求可对分词词库进行手工维护。

    思路:

    IK自定义词库是支持远程热加载的。

    先看下官方的说明:

    remote_ext_dict:

    1.该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。

    2.该 http 请求返回的内容格式是一行一个分词,换行符用 即可。

     

    满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。

    由此,我们可以开放一个API供IK调用。

    搜索分词(关键词)架构思路

    1.管理端对关键词进行维护;

    2.管理端设置秘钥(此秘钥仅做加载分词API验证使用);

    3.管理端展示分词列表,根据最后修改时间倒序展示。

    时序图:

    数据结构:

    关键词表(es_custom_words):

    字段名 

    提示文字

    类型

    长度

    是否主键

    id

    id

    int

    10

    name

    关键词

    字符串

    100

    add_time

    添加时间

    长整型

    20

    modify_time

    最后修改时间

    长整型

    20

    disabled

    是否可用:可用:1 ;隐藏: 0

    整形

    1

    秘钥设置说明: 在系统设置表(es_setting)中新增分组(ES_SIGN),对秘钥进行维护时修改此分组下的数据。

    领域模型

    管理端

    管理端添加搜索设置菜单,对关键词进行维护

    模型

    属性 

    说明

    备注

    id

    id

     

    name

    分词名称必填

     

    addTime

    添加时间

     

    disabled

    是否可用

    可用:1;不可用:0

    modifyTime

    修改时间

     

    ES加载词库API

    在基础API中添加加载词库API,此Api需要校验秘钥,失败返回空字符串,成功则从数据库中加载数据并返回。

    IK Analyzer 扩展配置如下:

    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
    3 <properties>
    4         <comment>IK Analyzer 扩展配置</comment>
    5         <!--用户可以在这里配置远程扩展字典 -->
    6         <entry key="remote_ext_dict">http://base-api-domain/load-customwords?secret_key=secret_value</entry>
    7 </properties>

    其中secret_value可以随意设置,此处配置的值,需要在管理端搜索分词列表处保存

    base-api-domain改为自己的base-api域名或者IP:端口即可

    源码

     ​说明:此处仅展示IK加载片段代码,关于管理分此维护相关不做展示

    CustomWordsBaseController

     1 package com.enation.app.javashop.base.api;
     2 
     3 import com.enation.app.javashop.core.base.SettingGroup;
     4 import com.enation.app.javashop.core.client.system.SettingClient;
     5 import com.enation.app.javashop.core.goods.GoodsErrorCode;
     6 import com.enation.app.javashop.core.goodssearch.model.EsSecretSetting;
     7 import com.enation.app.javashop.core.goodssearch.service.CustomWordsManager;
     8 import com.enation.app.javashop.framework.exception.ServiceException;
     9 import com.enation.app.javashop.framework.util.JsonUtil;
    10 import com.enation.app.javashop.framework.util.StringUtil;
    11 import io.swagger.annotations.Api;
    12 import io.swagger.annotations.ApiImplicitParam;
    13 import io.swagger.annotations.ApiImplicitParams;
    14 import org.springframework.beans.factory.annotation.Autowired;
    15 import org.springframework.web.bind.annotation.GetMapping;
    16 import org.springframework.web.bind.annotation.RequestMapping;
    17 import org.springframework.web.bind.annotation.RestController;
    18 import springfox.documentation.annotations.ApiIgnore;
    19 
    20 /**
    21  * 自定义分词控制器
    22  *
    23  * @author liuyulei
    24  * @version v1.0
    25  * @since v7.0.0
    26  * 2019-05-26
    27  */
    28 @RestController
    29 @RequestMapping("/load-customwords")
    30 @Api(description = "加载分词库")
    31 public class CustomWordsBaseController {
    32 
    33     @Autowired
    34     private CustomWordsManager customWordsManager;
    35     @Autowired
    36     private SettingClient settingClient;
    37 
    38     @GetMapping
    39     @ApiImplicitParams({
    40             @ApiImplicitParam(name = "secret_key", value = "秘钥", required = true, dataType = "String", paramType = "query")
    41 
    42     })
    43     public String getCustomWords(@ApiIgnore  String secretKey){
    44 
    45         if(StringUtil.isEmpty(secretKey)){
    46             return "";
    47         }
    48         String value = settingClient.get(SettingGroup.ES_SIGN);
    49         if(StringUtil.isEmpty(value)){
    50             return "";
    51         }
    52         EsSecretSetting secretSetting = JsonUtil.jsonToObject(value,EsSecretSetting.class);
    53         if(!secretKey.equals(secretSetting.getSecretKey())){
    54             throw new ServiceException(GoodsErrorCode.E310.code(),"秘钥验证失败!");
    55         }
    56         String res = this.customWordsManager.deploy();
    57         try {
    58             return new String(res.getBytes(),"utf-8");
    59         }catch (Exception e){
    60             e.printStackTrace();
    61         }
    62         return "";
    63 
    64     }
    65 
    66 
    67 }

    CustomWordsManager

     1 package com.enation.app.javashop.core.goodssearch.service;
     2 
     3 /**
     4  * 自定义分词表业务层
     5  * @author fk
     6  * @version v1.0
     7  * @since v7.0.0
     8  * 2018-06-20 16:08:07
     9  *
    10  * * update by liuyulei 2019-05-27
    11  */
    12 public interface CustomWordsManager    {
    13 
    14    /**
    15     * 部署替换
    16     * @return
    17     */
    18     String deploy();
    19 
    20 }

    CustomWordsManagerImpl

     1 package com.enation.app.javashop.core.goodssearch.service.impl;
     2 
     3 import com.enation.app.javashop.core.goodssearch.model.CustomWords;
     4 import com.enation.app.javashop.core.goodssearch.service.CustomWordsManager;
     5 import com.enation.app.javashop.framework.context.ThreadContextHolder;
     6 import com.enation.app.javashop.framework.database.DaoSupport;
     7 import com.enation.app.javashop.framework.util.DateUtil;
     8 import com.enation.app.javashop.framework.util.StringUtil;
     9 import org.springframework.beans.factory.annotation.Autowired;
    10 import org.springframework.beans.factory.annotation.Qualifier;
    11 import org.springframework.stereotype.Service;
    12 
    13 import javax.servlet.http.HttpServletResponse;
    14 import java.text.SimpleDateFormat;
    15 import java.util.List;
    16 
    17 /**
    18  * 自定义分词表业务类
    19  *
    20  * @author fk
    21  * @version v1.0
    22  * @since v7.0.0
    23  * 2018-06-20 16:08:07
    24  *
    25  * update by liuyulei 2019-05-27
    26  */
    27 @Service
    28 public class CustomWordsManagerImpl implements CustomWordsManager {
    29 
    30     @Autowired
    31     @Qualifier("goodsDaoSupport")
    32     private DaoSupport daoSupport;
    33 
    34     @Override
    35     public String deploy() {
    36         String sql = "select * from es_custom_words where disabled = 1 order by modify_time desc";
    37         List<CustomWords> list = this.daoSupport.queryForList(sql, CustomWords.class);
    38         HttpServletResponse response = ThreadContextHolder.getHttpResponse();
    39         StringBuffer buffer = new StringBuffer();
    40         if (StringUtil.isNotEmpty(list)) {
    41             int i = 0;
    42             for (CustomWords word : list) {
    43                 if (i == 0) {
    44                     SimpleDateFormat format =   new SimpleDateFormat( "yyyy-MM-dd hh:mm:ss" );
    45                     try {
    46                         response.setHeader("Last-Modified", format.parse(DateUtil.toString(word.getAddTime(),"yyyy-MM-dd hh:mm:ss")) + "");
    47                         response.setHeader("ETag", format.parse(DateUtil.toString(word.getModifyTime(),"yyyy-MM-dd hh:mm:ss")) + "");
    48                     }catch (Exception e){
    49                         e.printStackTrace();
    50                     }
    51 
    52                     buffer.append(word.getName());
    53                 } else {
    54                     buffer.append("
    " + word.getName());
    55                 }
    56                 i++;
    57             }
    58         }
    59         return buffer.toString();
    60     }
    61 }

    以上为此次分享内容,后续每周会不定期分享架构文章,大家可以关注我们!!!

                                                                                                                 易族智汇(javashop)原创文章 

  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/javashop-docs/p/12768014.html
Copyright © 2011-2022 走看看