ElasticSearch搜索引擎在SpringBoot中的實(shí)踐

Profile

實(shí)驗(yàn)環(huán)境

  • ES版本:5.3.0
  • spring bt版本:1.5.9

首先當(dāng)然需要安裝好elastic search環(huán)境髓涯,最好再安裝上可視化插件 elasticsearch-head來(lái)便于我們直觀地查看數(shù)據(jù)。

當(dāng)然這部分可以參考本人的帖子:
《centos7上elastic search安裝填坑記》
http://www.reibang.com/p/04f4d7b4a1d3

我的ES安裝在http://113.209.119.170:9200/ 這個(gè)地址(該地址需要配到springboot項(xiàng)目中去)

注: 本文原載于 My Personal Blog:扑庞, CodeSheep · 程序羊


Spring工程創(chuàng)建

這部分沒(méi)有特殊要交代的,但有幾個(gè)注意點(diǎn)一定要當(dāng)心

  • 注意在新建項(xiàng)目時(shí)記得勾選web和NoSQL中的Elasticsearch依賴(lài),來(lái)張圖說(shuō)明一下吧:
創(chuàng)建工程時(shí)勾選Nosql中的es依賴(lài)選項(xiàng)

項(xiàng)目自動(dòng)生成以后pom.xml中會(huì)自動(dòng)添加spring-boot-starter-data-elasticsearch的依賴(lài):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
  • 本項(xiàng)目中我們使用開(kāi)源的基于restful的es java客戶(hù)端jest掰烟,所以還需要在pom.xml中添加jest依賴(lài):
        <dependency>
            <groupId>io.searchbox</groupId>
            <artifactId>jest</artifactId>
        </dependency>
  • 除此之外還必須添加jna的依賴(lài):
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
        </dependency>

否則啟動(dòng)spring項(xiàng)目的時(shí)候會(huì)報(bào)JNA not found. native methods will be disabled.的錯(cuò)誤:

JNA not found. native methods will be disabled.
  • 項(xiàng)目的配置文件application.yml中需要把es服務(wù)器地址配置對(duì)
server:
  port: 6325

spring:
  elasticsearch:
    jest:
      uris:
      - http://113.209.119.170:9200  # ES服務(wù)器的地址!
      read-timeout: 5000

代碼組織

我的項(xiàng)目代碼組織如下:


項(xiàng)目代碼組織

各部分代碼詳解如下沐批,注釋都有:

  • Entity.java
package com.hansonwang99.springboot_es_demo.entity;
import java.io.Serializable;
import org.springframework.data.elasticsearch.annotations.Document;

public class Entity implements Serializable{

    private static final long serialVersionUID = -763638353551774166L;

    public static final String INDEX_NAME = "index_entity";

    public static final String TYPE = "tstype";

    private Long id;

    private String name;

    public Entity() {
        super();
    }

    public Entity(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

  • TestService.java
package com.hansonwang99.springboot_es_demo.service;

import com.hansonwang99.springboot_es_demo.entity.Entity;

import java.util.List;

public interface TestService {

    void saveEntity(Entity entity);

    void saveEntity(List<Entity> entityList);

    List<Entity> searchEntity(String searchContent);
}
  • TestServiceImpl.java

package com.hansonwang99.springboot_es_demo.service.impl;

import java.io.IOException;
import java.util.List;

import com.hansonwang99.springboot_es_demo.entity.Entity;
import com.hansonwang99.springboot_es_demo.service.TestService;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.Bulk;
import io.searchbox.core.Index;
import io.searchbox.core.Search;

@Service
public class TestServiceImpl implements TestService {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImpl.class);

    @Autowired
    private JestClient jestClient;

    @Override
    public void saveEntity(Entity entity) {
        Index index = new Index.Builder(entity).index(Entity.INDEX_NAME).type(Entity.TYPE).build();
        try {
            jestClient.execute(index);
            LOGGER.info("ES 插入完成");
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
        }
    }


    /**
     * 批量保存內(nèi)容到ES
     */
    @Override
    public void saveEntity(List<Entity> entityList) {
        Bulk.Builder bulk = new Bulk.Builder();
        for(Entity entity : entityList) {
            Index index = new Index.Builder(entity).index(Entity.INDEX_NAME).type(Entity.TYPE).build();
            bulk.addAction(index);
        }
        try {
            jestClient.execute(bulk.build());
            LOGGER.info("ES 插入完成");
        } catch (IOException e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
        }
    }

    /**
     * 在ES中搜索內(nèi)容
     */
    @Override
    public List<Entity> searchEntity(String searchContent){
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //searchSourceBuilder.query(QueryBuilders.queryStringQuery(searchContent));
        //searchSourceBuilder.field("name");
        searchSourceBuilder.query(QueryBuilders.matchQuery("name",searchContent));
        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(Entity.INDEX_NAME).addType(Entity.TYPE).build();
        try {
            JestResult result = jestClient.execute(search);
            return result.getSourceAsObjectList(Entity.class);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
            e.printStackTrace();
        }
        return null;
    }
}

  • EntityController.java
package com.hansonwang99.springboot_es_demo.controller;

import java.util.ArrayList;
import java.util.List;

import com.hansonwang99.springboot_es_demo.entity.Entity;
import com.hansonwang99.springboot_es_demo.service.TestService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/entityController")
public class EntityController {


    @Autowired
    TestService cityESService;

    @RequestMapping(value="/save", method=RequestMethod.GET)
    public String save(long id, String name) {
        System.out.println("save 接口");
        if(id>0 && StringUtils.isNotEmpty(name)) {
            Entity newEntity = new Entity(id,name);
            List<Entity> addList = new ArrayList<Entity>();
            addList.add(newEntity);
            cityESService.saveEntity(addList);
            return "OK";
        }else {
            return "Bad input value";
        }
    }

    @RequestMapping(value="/search", method=RequestMethod.GET)
    public List<Entity> save(String name) {
        List<Entity> entityList = null;
        if(StringUtils.isNotEmpty(name)) {
            entityList = cityESService.searchEntity(name);
        }
        return entityList;
    }
}

實(shí)際實(shí)驗(yàn)

增加幾條數(shù)據(jù),可以使用postman工具蝎亚,也可以直接在瀏覽器中輸入九孩,如增加以下5條數(shù)據(jù):

http://localhost:6325/entityController/save?id=1&name=南京中山陵
http://localhost:6325/entityController/save?id=2&name=中國(guó)南京師范大學(xué)
http://localhost:6325/entityController/save?id=3&name=南京夫子廟
http://localhost:6325/entityController/save?id=4&name=杭州也非常不錯(cuò)
http://localhost:6325/entityController/save?id=5&name=中國(guó)南邊好像沒(méi)有叫帶京字的城市了

數(shù)據(jù)插入效果如下(使用可視化插件elasticsearch-head觀看):


數(shù)據(jù)插入效果

我們來(lái)做一下搜索的測(cè)試:例如我要搜索關(guān)鍵字“南京”
我們?cè)跒g覽器中輸入:

http://localhost:6325/entityController/search?name=南京

搜索結(jié)果如下:

關(guān)鍵字“南京”的搜索結(jié)果

剛才插入的5條記錄中包含關(guān)鍵字“南京”的四條記錄均被搜索出來(lái)了!

當(dāng)然這里用的是standard分詞方式发框,將每個(gè)中文都作為了一個(gè)term躺彬,凡是包含“南”、“京”關(guān)鍵字的記錄都被搜索了出來(lái),只是評(píng)分不同而已宪拥,當(dāng)然還有其他的一些分詞方式仿野,此時(shí)需要其他分詞插件的支持,此處暫不涉及她君,后文中再做探索脚作。


后記

由于能力有限,若有錯(cuò)誤或者不當(dāng)之處缔刹,還請(qǐng)大家批評(píng)指正球涛,一起學(xué)習(xí)交流!



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末校镐,一起剝皮案震驚了整個(gè)濱河市亿扁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸟廓,老刑警劉巖从祝,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異引谜,居然都是意外死亡牍陌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)煌张,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)呐赡,“玉大人,你說(shuō)我怎么就攤上這事骏融×脆郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵档玻,是天一觀的道長(zhǎng)怀泊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)误趴,這世上最難降的妖魔是什么霹琼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮凉当,結(jié)果婚禮上枣申,老公的妹妹穿的比我還像新娘。我一直安慰自己看杭,他們只是感情好忠藤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著楼雹,像睡著了一般模孩。 火紅的嫁衣襯著肌膚如雪尖阔。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天榨咐,我揣著相機(jī)與錄音介却,去河邊找鬼。 笑死块茁,一個(gè)胖子當(dāng)著我的面吹牛齿坷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播龟劲,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼胃夏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了昌跌?” 一聲冷哼從身側(cè)響起仰禀,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚕愤,沒(méi)想到半個(gè)月后答恶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萍诱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年悬嗓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裕坊。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡包竹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出籍凝,到底是詐尸還是另有隱情周瞎,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布饵蒂,位于F島的核電站声诸,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏退盯。R本人自食惡果不足惜彼乌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渊迁。 院中可真熱鬧慰照,春花似錦、人聲如沸琉朽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)漓骚。三九已至蝌衔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝌蹂,已是汗流浹背噩斟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留孤个,地道東北人剃允。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像齐鲤,于是被迫代替她去往敵國(guó)和親斥废。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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