SpringBoot 整合ElasticSearch基础

SpringBoot 整合ElasticSearch基础,第1张

SpringBoot 整合ElasticSearch基础

SpringBoot 整合ElasticSearch基础
持续更新…

建议读者先学习这儿的前置知识…

入门工程

大致工程结构图:

引入主要依赖:


    com.alibaba
    fastjson
    1.2.71



    org.springframework.boot
    spring-boot-starter-data-elasticsearch


    org.springframework.boot
    spring-boot-starter-web


    org.projectlombok
    lombok
    true

新建配置类:

package cn.wu.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ESConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
                RestClient.builder( // 构建连接对象
                        new HttpHost("127.0.0.1",9200,"http")));
        return restHighLevelClient;
    }
}

新建业务层:

package cn.wu.service;

import cn.wu.pojo.Book;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.Timevalue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service("esServiceBean")
public class ESService {

    private RestHighLevelClient restHighLevelClient;

    @Autowired
    @Qualifier("restHighLevelClient")
    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }
    // 创建索引
    public Boolean createIndex(String indexName){
        try{
            // 1.创建索引 *** 作对象请求
            CreateIndexRequest indexRequest = new CreateIndexRequest(indexName);
            // 2.客户端执行请求
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices()
                    .create(indexRequest, RequestOptions.DEFAULT);
            return true;
        }catch (IOException e){
            return false;
        }
    }

    // 判断索引是否存在
    public Boolean existIndex(String indexName){
        // 1.创建索引 *** 作对象请求
        GetIndexRequest indexRequest = new GetIndexRequest(indexName);
        // 2.客户端执行请求判断索引是否存在
        Boolean flag = false;
        try{
            flag = restHighLevelClient.indices().exists(indexRequest,RequestOptions.DEFAULT);
        }catch(IOException e){}
        return flag;
    }
    // 删除索引
    public Boolean deleteIndex(String indexName){
        // 1.创建索引 *** 作对象请求
        DeleteIndexRequest indexRequest = new DeleteIndexRequest(indexName);
        // 2.客户端执行请求删除索引
        Boolean flag = false;
        AcknowledgedResponse acknowledgedResponse = null;
        try{
            acknowledgedResponse = restHighLevelClient.indices().delete(indexRequest, RequestOptions.DEFAULT);
        }catch(IOException e){}
        if(acknowledgedResponse != null){
            flag = acknowledgedResponse.isAcknowledged(); // 获取状态
        }
        return flag;
    }

    // 添加对应ID的文档(Book)
    public Boolean addBook(String indexName,String id,Book book){
        // 1.创建索引 *** 作对象请求
        IndexRequest indexRequest = new IndexRequest(indexName);
        // 2.配置规则属性
        indexRequest.id(id);
        indexRequest.timeout("1s"); // 过期时间设置

        // 3.返回的数据转化为Json
        indexRequest.source(JSON.toJSONString(book), XContentType.JSON);
        // 4.客户端发送请求
        try{
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
            log.info("响应对象为: "+indexResponse.toString());
            log.info("响应状态为: "+indexResponse.status().toString());
            return true;
        }catch(IOException e){
            return false;
        }
    }
    // 判断文档(Book)是否存在
    public Boolean existBook(String indexName,String id){
        // 1.创建索引 *** 作对象请求
        GetRequest getRequest = new GetRequest(indexName,id);
        // 2.客户端发送请求
        try{
            return restHighLevelClient.exists(getRequest,RequestOptions.DEFAULT);
        }catch(IOException e){
            return false;
        }
    }
    // 获取文档(Book)_source信息
    public Map getBook(String indexName, String id){
        // 1.创建索引 *** 作对象请求
        GetRequest getRequest = new GetRequest(indexName,id);
        // 2.客户端发送请求
        GetResponse getResponse = null;
        try{
            getResponse = restHighLevelClient.get(getRequest,RequestOptions.DEFAULT);
            return getResponse.getSource();
        }catch(IOException e){
            return null;
        }
    }
    // 更新文档(Book)信息 局部修改方式
    public Boolean updateBook(String indexName,String id,Book book){
        // 1.创建索引 *** 作对象请求
        UpdateRequest updateRequest = new UpdateRequest(indexName,id);
        // 2.客户端发送请求
        UpdateResponse updateResponse = null;
        try{
            updateRequest.doc(JSON.toJSONString(book),XContentType.JSON);
            updateResponse = restHighLevelClient.update(updateRequest,RequestOptions.DEFAULT);
            log.info("更新文档: "+updateResponse.status());
            return true;
        }catch(IOException e){
            return  false;
        }
    }
    // 删除文档(Book)
    public Boolean deleteBook(String indexName,String id){
        // 1.创建索引 *** 作对象请求
        DeleteRequest deleteRequest = new DeleteRequest(indexName,id);
        deleteRequest.timeout("1s");
        // 2.客户端发送请求
        DeleteResponse deleteResponse = null;
        try{
            deleteResponse = restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
            log.info("删除文档: "+deleteResponse.status());
            return true;
        }catch(IOException e){
            return false;
        }
    }
    // 批量添加文档(Book) 从startId位置开始连续批量添加
    public Boolean addBulkBook(String indexName, String startId, ArrayList books){
        // 1.创建索引 *** 作对象请求
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("3s");
        // 2.创建批处理请求
        int offset = Integer.parseInt(startId);
        for(int i = 0 ; i < books.size() ; i++){
            // 同理,批处理修改
            // UpdateRequest updateRequest = new UpdateRequest(indexName,startId);
            // 同理,批处理删除
            // DeleteRequest deleteRequest = new DeleteRequest(indexName,startId);

            IndexRequest indexRequest = new IndexRequest(indexName);
            indexRequest.id(offset+i+"");
            indexRequest.source(JSON.toJSONString(books.get(i)),XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        // 3.客户端发送请求
        try{
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
            log.info("批量添加文档: "+bulkResponse.status());
            return true;
        }catch(IOException e){
            return false;
        }
    }
    // 条件查询(重要) 这里以模糊匹配并高亮为例
    public Object searchBook(String indexName, String fieldName, String value){
        // 1.构建搜索请求
        SearchRequest searchRequest = new SearchRequest(indexName);
        // 2.构建搜索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 常用查询条件
        // 2.1 QueryBuilders.termQuery() 精确
        // TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(name,value);
        // searchSourceBuilder.query(termQueryBuilder);
        // 2.2 QueryBuilders.matchAllQuery() 查询全部
        // 2.3 QueryBuilders.boolQuery() 高级条件查询
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(fieldName,value);
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(fieldName); // 设置高亮字段
        highlightBuilder.preTags(""); // 设置高亮前缀
        highlightBuilder.postTags(""); // 设置高亮后缀
        highlightBuilder.requireFieldMatch(true); // 多个字段均高亮
        // 3.构造器绑定
        searchSourceBuilder.query(matchQueryBuilder);
        searchSourceBuilder.highlighter(highlightBuilder);
        searchSourceBuilder.timeout(new Timevalue(5, TimeUnit.SECONDS)); // 超时时间
        searchRequest.source(searchSourceBuilder);
        // 4.客户端发送请求 获取高亮数据
        try{
                SearchResponse searchResponse  = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
                SearchHits hits = searchResponse.getHits();
                ArrayList result = new ArrayList<>();
                for(SearchHit hit:hits){
                    Map highlightFields = hit.getHighlightFields();
                    Text[] texts = highlightFields.get(fieldName).getFragments();
                    String str = "";
                    for(Text text:texts){
                        str += text;
                    }
                    result.add(str);
                }
                return result;
        }catch(IOException e){
            return null;
        }
    }
}

新建控制层:

package cn.wu.controller;

import cn.wu.pojo.Book;
import cn.wu.service.ESService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Map;

@RestController
public class ESController {

    private ESService esService;

    @Autowired
    @Qualifier("esServiceBean")
    public void setEsService(ESService esService) {
        this.esService = esService;
    }

    @GetMapping("/create/index/{indexName}")
    public Boolean createIndex(@PathVariable("indexName") String indexName){
        return esService.createIndex(indexName);
    }

    @GetMapping("/exist/index/{indexName}")
    public Boolean existIndex(@PathVariable("indexName") String indexName){
        return esService.existIndex(indexName);
    }

    @GetMapping("/delete/index/{indexName}")
    public Boolean deleteIndex(@PathVariable("indexName") String indexName){
        return esService.deleteIndex(indexName);
    }

    @PostMapping("/add/{indexName}/{id}")
    public Boolean addBook(@RequestBody Book book,
                           @PathVariable("indexName") String indexName,
                           @PathVariable("id") String id){
        return esService.addBook(indexName,id,book);
    }

    @GetMapping("/exist/{indexName}/{id}")
    public Boolean existBook(@PathVariable("indexName") String indexName,
                           @PathVariable("id") String id){
        return esService.existBook(indexName,id);
    }

    @GetMapping("/get/{indexName}/{id}")
    public Map getBook(@PathVariable("indexName") String indexName,
                                       @PathVariable("id") String id){
        return esService.getBook(indexName,id);
    }

    @PostMapping("/update/{indexName}/{id}")
    public Boolean updateBook(@RequestBody Book book,
                                          @PathVariable("indexName") String indexName,
                                       @PathVariable("id") String id){
        return esService.updateBook(indexName,id,book);
    }

    @GetMapping("/delete/{indexName}/{id}")
    public Boolean deleteBook(@PathVariable("indexName") String indexName,
                              @PathVariable("id") String id){
        return esService.deleteBook(indexName,id);
    }

    @PostMapping("/add/bulk/{indexName}/{startId}")
    public Boolean addBulkBook(@PathVariable("indexName") String indexName,
                               @PathVariable("startId") String startId,
                               @RequestBody ArrayList books){
        return esService.addBulkBook(indexName,startId,books);
    }

    @GetMapping("/search/{indexName}/{fieldName}/{value}")
    public String searchBook(@PathVariable("indexName") String indexName,
                               @PathVariable("fieldName") String fieldName,
                              @PathVariable("value") String value){
        return esService.searchBook(indexName,fieldName,value);
    }
}

启动之前要先打开ES集群,测试结果:

首先新建book_index的索引


判断ES中是否存在book_index索引

删除book_index的索引


添加文档


判断相应ID的文档是否存在


获取相应ID的文档

修改相应ID的文档



删除相应ID的文档

批量连续添加特定起始ID的文档

条件查询

入门实战 测试结果

最终效果显示(这个是临时手搓的,页面很丑,主要还是看功能… )

以上基本实现了关键字标红…

构建后端

大致结构:

引入主要依赖


    1.8
    UTF-8
    UTF-8
    2.3.7.RELEASE



    org.jsoup
    jsoup
    1.10.2



    com.alibaba
    fastjson
    1.2.71


    org.springframework.boot
    spring-boot-starter-data-elasticsearch


    org.springframework.boot
    spring-boot-starter-web


    org.projectlombok
    lombok
    true


   
       
           org.springframework.boot
           spring-boot-dependencies
           ${spring-boot.version}
           pom
           import
       
   

appilcation.yml

server:
  port: 8888

主启动类

package cn.wu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ESApplication {
    public static void main(String[] args) {
        SpringApplication.run(ESApplication.class,args);
    }
}

ES配置类

package cn.wu.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ESConfig {
    @Bean("restHighLevelClient")
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
                RestClient.builder( // 构建连接对象
                        new HttpHost("127.0.0.1",9200,"http")));
        return restHighLevelClient;
    }
}

实体类

package cn.wu.pojo;

import lombok.Data;
import lombok.Setter;

@Data
@Setter
public class Book {
    private String bookName;
    private String bookPrice;
    private String bookUrl;
}

业务层

package cn.wu.service;

import cn.wu.pojo.Book;
import cn.wu.utils.HtmlUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.Timevalue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

@Slf4j
@Service("bookServiceBean")
public class BookService {

    private RestHighLevelClient restHighLevelClient;
    @Autowired
    @Qualifier("restHighLevelClient")
    public void setRestHighLevelClient(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    private HtmlUtil htmlUtil;

    @Autowired
    public void setHtmlUtil(HtmlUtil htmlUtil) {
        this.htmlUtil = htmlUtil;
    }

    
    public Boolean addBooks(String indexName,String startId,String keyword) {
        try {
            ArrayList books = htmlUtil.getBooks(keyword);
            BulkRequest bulkRequest = new BulkRequest();
            bulkRequest.timeout("4s");
            for(int i = 0 ; i < books.size() ; i++){
                IndexRequest indexRequest = new IndexRequest(indexName);
                indexRequest.id((startId+i)+"");
                bulkRequest.add(indexRequest.source(JSON.toJSONString(books.get(i)), XContentType.JSON));
            }
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            log.info("批处理添加的状态为: "+bulkResponse.status());
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    
    public ArrayList> searchBooks(String indexName,String fieldName,String keyword,int offset,int size){
        SearchRequest searchRequest = new SearchRequest(indexName);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(fieldName,keyword); // 模糊构建
        HighlightBuilder highlightBuilder = new HighlightBuilder(); // 高亮构建
        highlightBuilder.field(fieldName);
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");
        highlightBuilder.requireFieldMatch(true); // 同一字段值下所有的匹配所有

        // 高亮配置
        searchSourceBuilder.highlighter(highlightBuilder);
        // 条件匹配配置
        searchSourceBuilder.query(matchQueryBuilder);
        // 超时配置
        searchSourceBuilder.timeout(Timevalue.timevalueSeconds(4));
        // 分页配置
        searchSourceBuilder.from(offset);
        searchSourceBuilder.size(size);

        // 执行请求
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
            ArrayList> result = new ArrayList<>();
            for(SearchHit searchHit : searchResponse.getHits().getHits()){
//                Map fields = searchHit.getSourceAsMap();
//                result.add(fields);
                Map highlightFieldMap = searchHit.getHighlightFields();
                HighlightField highlightField = highlightFieldMap.get(fieldName);
                Map fields = searchHit.getSourceAsMap();
                if(highlightField != null){
                    Text[] fragments = highlightField.fragments();
                    String temp = "";
                    for(Text text:fragments ){
                        temp += text;
                    }
                    fields.put(fieldName,temp); // 替换
                    result.add(fields);
                }
            }
            return result;
        } catch (IOException e) {
           return null;
        }
    }

}

爬虫工具类(爬取京东书籍信息)

package cn.wu.utils;

import cn.wu.pojo.Book;
import org.jsoup.Jsoup;
import org.jsoup.nodes.document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;

@Component
public class HtmlUtil {

//    public static void main(String[] args) throws IOException {
//        // 获取请求
//        String baseUrl = "https://search.jd.com/Search?keyword=";
//        String keyword = "SpringCloud";
//
//        ArrayList books = getBooks(baseUrl,keyword);
//        System.out.println(books.toString());
//    }
    public ArrayList getBooks(String keyword) throws  IOException{
        String url = "https://search.jd.com/Search?keyword="+keyword;
        ArrayList result = new ArrayList<>();
        document document = Jsoup.connect(url).get();
        Element element = document.getElementById("J_goodsList");
        Elements elements = element.getElementsByTag("li");

        for(Element e:elements){
            String img = e.getElementsByTag("img").eq(0).attr("data-lazy-img");
            String price = e.getElementsByClass("p-price").eq(0).text();
            String name = e.getElementsByClass("p-name").eq(0).text();

            Book book = new Book();
            book.setBookName(name);
            book.setBookUrl(img);
            book.setBookPrice(price);
            result.add(book);
        }
        return result;
    }
}

控制层

package cn.wu.pojo;

import lombok.Data;
import lombok.Setter;

@Data
@Setter
public class Book {
    private String bookName;
    private String bookPrice;
    private String bookUrl;
}

控制层

package cn.wu.controller;

import cn.wu.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Map;

@RestController
public class BookController {
    private BookService bookService;

    @Autowired
    @Qualifier("bookServiceBean")
    public void setBookService(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping("/add/bulk/{indexName}/{startId}/{keyword}")
    public Boolean addBulkBooks(@PathVariable("indexName") String indexName,
                                @PathVariable("startId") String startId,
                                @PathVariable("keyword") String keyword){
        return bookService.addBooks(indexName, startId, keyword);
    }
    @GetMapping("/search/{indexName}/{fieldName}/{keyword}/{offset}/{size}")
    public ArrayList> searchBooks(@PathVariable("indexName") String indexName,
                                                     @PathVariable("fieldName") String fieldName,
                                                     @PathVariable("keyword") String keyword,
                                                     @PathVariable("offset") Integer offset,
                                                     @PathVariable("size") Integer size){
        return bookService.searchBooks(indexName,fieldName,keyword,offset,size);
    }
}

构建前端

这儿读者需要事先安装node.js以及vue-cli,相关内容读者可以查看这里…

选择一个文件夹,执行vue create elasticsearch-vue,修改后的大致结构为:

vue.config.js(跨域问题解决)

module.exports = {
    devServer:{
        proxy:{
            '/api':{ // 设置拦截器
                target: 'http://localhost:8888', // 设置代理目标地址
                changeOrigin: true, //是否设置同源
                pathRewrite:{
                    '/api':'' // 代理之后将/api替换为空字符串
                }
            }
        }
    }
}

App.vue