熱點平臺搭建(四)——Springboot+Elasticsearch實現(xiàn)歷史熱點搜索

使用Elasticsearch查詢歷史熱點消息汉嗽,搜索的內(nèi)容包括:根據(jù)關(guān)鍵詞搜索,可以多個關(guān)鍵詞稳析;根據(jù)熱點標題查找歷史熱度值變化撵孤。

搜索框DTO

用來接收前端傳遞的搜索框內(nèi)容竭望。

@Data
public class SearchKeywords {
    @NotEmpty
    private String keywords;
    @NotEmpty
    private String relation;
    @NotEmpty
    @NotNull
    private String type;
}

定義SeachData接收從ES返回的數(shù)據(jù)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SearchData {
    private String titleText;
    private String titleKeyword;
    private Integer rank;
    private Integer hotNumber;
    private String timestamp;
    private Integer uId;
}

服務(wù)接口

public interface SearchService {
    /**
     * 根據(jù)標題查找歷史信息
     * @param title 標題
     * @param type 哪個表
     * @return 歷史信息
     */
    public List<SearchData> searchByName(String title, String type);

    /**
     * 根據(jù)關(guān)鍵詞查找
     * @param keyword 關(guān)鍵詞
     * @param type 表名
     * @param relation 關(guān)鍵詞之間的關(guān)系
     * @return 歷史信息
     */
    public List<SearchData> searchByKeyword(String keyword, String type, String relation);

    /**
     * 根據(jù)uId查找內(nèi)容詳情
     * @param type 熱榜名稱
     * @param uId 唯一鍵
     * @return 詳情
     */
    public List<SearchDetail> searchDetail(String type, int uId);
}

包括兩個查詢內(nèi)容邪码,還包含了一個根據(jù)uId查找歷史消息咬清,uId在數(shù)據(jù)庫中建立了索引旧烧。

服務(wù)實現(xiàn)

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private EsUtil esUtil;

    @Autowired
    private SearchDetailMapper searchDetailMapper;

    @Override
    public List<SearchData> searchByName(String title, String type) {
        // 創(chuàng)建bool query
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // 查找title_keyword中有查找的關(guān)鍵詞
        boolQueryBuilder.filter(QueryBuilders.termQuery("title_keyword", title));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(boolQueryBuilder);
        // 根據(jù)時間倒序
        builder.sort("timestamp", SortOrder.ASC);
        // 取前30個
        builder.size(30);
        return esUtil.search(type+"_data", builder, SearchData.class);
    }

    @Override
    public List<SearchData> searchByKeyword(String keyword, String type, String relation) {
        // 創(chuàng)建simple query string
        SimpleQueryStringBuilder simpleQueryStringBuilder = new SimpleQueryStringBuilder(keyword);
        // 根據(jù)title_text匹配
        simpleQueryStringBuilder.field("title_text");
        // 關(guān)鍵詞關(guān)系有和與或
        if("OR".equals(relation) || "or".equals(relation)){
            simpleQueryStringBuilder.defaultOperator(Operator.OR);
        }else {
            simpleQueryStringBuilder.defaultOperator(Operator.AND);
        }
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(simpleQueryStringBuilder);
        builder.sort("timestamp", SortOrder.DESC);
        // 找出歷史排序最高的一條
        CollapseBuilder collapseBuilder = new CollapseBuilder("title_keyword");
        InnerHitBuilder innerHitBuilder = new InnerHitBuilder("top_hot");
        innerHitBuilder.setSize(1);
        SortBuilder sortBuilder = SortBuilders.fieldSort("hot_number").order(SortOrder.DESC);
        innerHitBuilder.addSort(sortBuilder);
        collapseBuilder.setInnerHits(innerHitBuilder);
        builder.collapse(collapseBuilder);
        builder.size(30);
        return esUtil.search(type+"_data", builder, SearchData.class);
    }

    @Override
    public List<SearchDetail> searchDetail(String type, int uId) {
        return searchDetailMapper.queryDetail(type, uId);
    }
}

EsUtil

ES實現(xiàn)工具類

@Component
public class EsUtil {
    @Value("${es.host}")
    private String host;
    @Value("${es.port}")
    private int port;
    @Value("${es.scheme}")
    private String scheme;

    private static RestHighLevelClient client = null;

    @PostConstruct
    public void init() {
        try {
            if (client != null) {
                client.close();
            }
            client = new RestHighLevelClient(RestClient.builder(new HttpHost(host, port, scheme)));
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Description: 搜索
     *
     * @param index   index
     * @param builder 查詢參數(shù)
     * @param c       結(jié)果類對象
     * @return java.util.ArrayList
     * @author fanxb
     * @date 2019/7/25 13:46
     */
    public <T> List<T> search(String index, SearchSourceBuilder builder, Class<T> c) {
        SearchRequest request = new SearchRequest(index);
        request.source(builder);
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            List<T> res = new ArrayList<>(hits.length);
            for (SearchHit hit : hits) {
                res.add(JSON.parseObject(hit.getSourceAsString(), c));
            }
            return res;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Controller

@Controller
@RequestMapping("/search")
public class searchController {

    private static Logger logger = LoggerFactory.getLogger(IndexController.class);

    @Resource
    SearchService searchService;

    @RequestMapping(value = "/searchTitle", method = RequestMethod.GET)
    public String searchTitle(@RequestParam(value = "title") String title, @RequestParam(value = "type") String type ,ModelMap map){
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = userDetails.getUsername();
        logger.info("用戶名=" + name + "&行為=歷史熱度查看:" + title + "|" + type);

        map.addAttribute("titleData", title);
        List<String> time = new ArrayList<>();
        List<Integer> hotNumber = new ArrayList<>();
        List<SearchData> hotSpots = searchService.searchByName(title, type);
        for (SearchData hotSpot: hotSpots){
            time.add(hotSpot.getTimestamp().replace('T', ' '));
            hotNumber.add(hotSpot.getHotNumber());
        }
        map.addAttribute("timeData", time);
        map.addAttribute("hotNumberData", hotNumber);
        return "search/searchTitle";
    }

    @RequestMapping(value = "/searchDetail", method = RequestMethod.GET)
    @ResponseBody
    public SearchDetail searchDetail(@RequestParam(value = "uId") int uId, @RequestParam(value = "type") String type ,ModelMap map){
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = userDetails.getUsername();
        logger.info("用戶名=" + name + "&行為=詳情查看:" + uId + "|" + type);
        List<SearchDetail> searchDetails = searchService.searchDetail(type, uId);
        return searchDetails.get(0);
    }

    @PostMapping(value = "/searchKeywords")
    public String searchKeywords(@ModelAttribute("searchKeywords") @Valid SearchKeywords searchKeywords, BindingResult result, Model model){
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = userDetails.getUsername();
        logger.info("用戶名=" + name + "&行為=關(guān)鍵詞查找:" + searchKeywords.getKeywords() + "|" + searchKeywords.getType() + "|" + searchKeywords.getRelation());

        if (result.hasErrors()){
            return "search/searchKeywords";
        }
        String type = getTypeName(searchKeywords.getType());
        List<SearchData> searchHotSpotData = searchService.searchByKeyword(searchKeywords.getKeywords(), type, searchKeywords.getRelation());
        model.addAttribute("searchHotSpotData", searchHotSpotData);
        model.addAttribute("dataType", type);
        return "search/searchKeywords";
    }

    @GetMapping(value = "/searchKeywords")
    public String toSearchKeywords(Model model){
        model.addAttribute("searchKeywords", new SearchKeywords());
        return "search/searchKeywords";
    }

    private String getTypeName(String type) {
        switch (type){
            case "微博":
                return "weibo";
            case "爬客":
                return "niuke";
            case "虎撲":
                return "hupu";
            case "掘金":
                return "juejin";
            default:
                return "weibo";
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劳曹,一起剝皮案震驚了整個濱河市琅摩,隨后出現(xiàn)的幾起案子迫吐,更是在濱河造成了極大的恐慌志膀,老刑警劉巖溉浙,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件馆蠕,死亡現(xiàn)場離奇詭異互躬,居然都是意外死亡吼渡,警方通過查閱死者的電腦和手機寺酪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門寄雀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盒犹,“玉大人阿趁,你說我怎么就攤上這事脖阵∶” “怎么了悍募?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵洋魂,是天一觀的道長副砍。 經(jīng)常有香客問我庄岖,道長心剥,這世上最難降的妖魔是什么背桐? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任畦娄,我火速辦了婚禮捍掺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘曲横。我一直安慰自己灾杰,他們只是感情好熙参,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著栏渺,像睡著了一般磕诊。 火紅的嫁衣襯著肌膚如雪霎终。 梳的紋絲不亂的頭發(fā)上神僵,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音炮障,去河邊找鬼。 笑死白筹,一個胖子當著我的面吹牛系馆,可吹牛的內(nèi)容都是我干的由蘑。 我是一名探鬼主播尼酿,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼土辩!你這毒婦竟也來了拷淘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎松忍,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摊溶,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年惰爬,在試婚紗的時候發(fā)現(xiàn)自己被綠了补鼻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咨跌。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刊殉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遍膜,我是刑警寧澤瓢颅,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布木人,位于F島的核電站角塑,受9級特大地震影響圃伶,放射性物質(zhì)發(fā)生泄漏窒朋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一唧取、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淡诗,春花似錦、人聲如沸群凶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛾坯,卻和暖如春脉课,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呈驶。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留聋迎,地道東北人脂矫。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像砌庄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奕枢,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容