springboot整合es6.4

之前一直没有写博客的习惯,但看到无数小伙伴都有自己的博客,加上最近开始做微服务的实战项目了,缕缕续续的会搭建一些环境,心里有点蠢蠢欲动.....记录下几周前搭建的过程,先从es开始写,照着别人的从环境搭建到postman测试踩了不少坑。

centos7上的环境搭建:

1. docker pull elasticsearch:6.4.0

2. 运行es

docker run -d --name es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms300m -Xmx300m" -e "discovery.type=single-node" docker.io/elasticsearch:6.4.0

-xms 初始内存 -xmx最大内存 ,我的是学生机1核2G之前按照默认的来会爆炸.....

 

3. 进入es修改配置文件:

docker exec -it es /bin/bash

cd /usr/share/elasticsearch/config/

vi elasticsearch.yml

cluster.name: recommend     
network.host: 0.0.0.0    //不写0.0.0.0有可能在idea上报错,玄学问题.
http.port: 9200
transport.tcp.port: 9300
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["xx.xxx.xxx.xxx:9300"]
discovery.zen.minimum_master_nodes: 1
node.ingest: true
bootstrap.memory_lock: false
node.max_local_storage_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: /.*/

4.安装ik分词器

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.0/elasticsearch-analysis-ik-6.4.0.zip

重启下es

es环境搭建好了,开始在idea上配置

1.导入依赖

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>6.4.0</version>  
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>6.4.0</version>
</dependency>
2. application.yml的配置

3.获取yml中的配置信息:
@Component
@ConfigurationProperties(prefix = "elasticsearch")
@Data
public class ESProperties {

     private String ip;
     private String port;
     private String pool;
     private String clusterName;
     private String nodeName;

 }

 

4.配置类:

@Configuration
public class ESConfig {
    @Autowired
     private ESProperties esProperties;


     /**
      * @author 刘其佳
      * @description
      *      创建并初始化TransportClient对象,使用该对象对ES进行增删查改
      *      cluster.name:集群名字
      *      node.name:节点名字
      *      client.transport.sniff:客户端(Java项目)一致监视ES的节点状态(节点数),不再需要手动添加节点,如果有新的节点产生了,会自动加载进项目中
      *      thread_pool.search.size:线程池
      *
      * @param * param *:
      * @date 2019/9/18
      * @return org.elasticsearch.client.transport.TransportClient
      * @throws
      */
     @Bean("transportClient")
     public TransportClient getTransportClient(){
         //1、创建TransportClient对象
         TransportClient transportClient=null;
         try{
                //2、设置Java对ES的集群信息
                 Settings settings=Settings.builder().put("cluster.name",esProperties.getClusterName())
                         .put("node.name", esProperties.getNodeName())
			之前按照别人的配置的,一直报错,花了一上午的时间,才注意到这里要为false,搭建es集群,为true
                         .put("client.transport.sniff", false) 
                         .put("thread_pool.search.size", esProperties.getPool()).build();
                 //3、初始化TransportClient对象
                 transportClient= new PreBuiltTransportClient(settings);
                 //4、配置对ES的连接信息
                 TransportAddress transportAddress=new TransportAddress(InetAddress.getByName(esProperties.getIp()),Integer.parseInt(esProperties.getPort()));
                 //5、把对ES的连接对象放到transportClient对象中
                 transportClient.addTransportAddress(transportAddress);
             }catch (UnknownHostException e){
                 e.printStackTrace();
             }
         return transportClient;
     }
}
5.工具类
import com.recommend.common.dto.Result;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;


public class ESUtil {

    @Resource
    private TransportClient client;

          /**
    * 创建索引
    *
    * @param index
    * @return
    */
      public  void createIndex(String index) {
         // isIndexExist:判断索引是否存在
         if (isIndexExist(index)) {
             throw new RuntimeException("重复创建索引");
         }
         CreateIndexResponse indexresponse = client.admin().indices().prepareCreate(index).execute().actionGet();
         // indexresponse.isAcknowledged():创建索引是否成功,return Boolean类型(true:表示成功,false:失败)
         if(!indexresponse.isAcknowledged()) {
             throw new RuntimeException("创建索引失败");
         }
     }

          /**
    * 删除索引
    *
    * @param index
    * @return
    */
      public void deleteIndex(String index) {
         if (!isIndexExist(index)) {
             throw new RuntimeException("索引不存在");
         }
         DeleteIndexResponse dResponse = client.admin().indices().prepareDelete(index).execute().actionGet();
         if (!dResponse.isAcknowledged()) {
             throw new RuntimeException("删除索引失败");
         }
     }

         /**
    * 判断索引是否存在
    *
    * @param index
    * @return
    */
     public boolean isIndexExist(String index) {
         IndicesExistsResponse inExistsResponse = client.admin().indices().exists(new IndicesExistsRequest(index)).actionGet();
         return inExistsResponse.isExists();
     }

         /**
    * @Author: LX
    * @Description: 判断index下指定type是否存在
    * @Date: // :
    * @Modified by:
    */
     public  boolean isTypeExist(String index, String type) {
         return isIndexExist(index)
                 ? client.admin().indices().prepareTypesExists(index).setTypes(type).execute().actionGet().isExists()
                 : false;
     }

             /**
        * 数据添加,正定ID
        *
        * @param mapObj 要增加的数据
        * @param index      索引,类似数据库
        * @param type       类型,类似表
        * @param id         数据ID
        * @return
        */
     public void addData(Map<String, Object> mapObj, String index, String type, String id) {
         IndexResponse response = client.prepareIndex(index, type, id).setSource(mapObj).get();
         // response.getId():就是添加数据后ES为这条数据所生成的id
         // 需要返回添加数据是否成功
         String status = response.status().toString();
         // 添加数据后所返回的状态(如果成功就是code:-->OK)
         // eq:sacii --> 小写字母和大写字母不一样
         // status:-->OK
         // ok
         if("OK".equals(status.toUpperCase())||"CREATED".equals(status.toUpperCase())) {

         } else {
             throw new RuntimeException("添加数据失败");
         }
     }

         /**
    * 数据添加
    *
    * @param mapObj 要增加的数据
    * @param index      索引,类似数据库
    * @param type       类型,类似表
    * @return
    */
     public void addData(Map<String, Object> mapObj, String index, String type) {
         addData(mapObj,index, type, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
     }

         /**
    * @author 刘其佳
    * @description
    *      将对象转化为map类型
    * @param * param *:object
    * @date //
    * @return java.util.Map<java.lang.String,java.lang.Object>
    * @throws
    */
     public Map<String, Object> objectTurnMap(Object object){
         Map<String, Object> result = new HashMap<String, Object>();
         //获得类的属性名  数组
         Field[] fields = object.getClass().getDeclaredFields();
         try {
                 for (Field field : fields) {
                         field.setAccessible(true);
                         String name = new String(field.getName());
                         result.put(name, field.get(object));
                     }
             }catch (Exception e){
                 e.printStackTrace();
             }
         return result;
     }

         /**
    * 通过ID删除数据
    *
    * @param index 索引,类似数据库
    * @param type  类型,类似表
    * @param id    数据ID
    */
     public void deleteDataById(String index, String type, String id) {

         DeleteResponse response = client.prepareDelete(index, type, id).execute().actionGet();
         if(!"OK".equals(response.status().toString().toUpperCase())) {
                throw new RuntimeException("删除数据失败或没有该数据");
         }
     }

         /**
    * 通过ID 更新数据
    *
    * @param mapObj 要增加的数据
    * @param index      索引,类似数据库
    * @param type       类型,类似表
    * @param id         数据ID
    * @return
    */
     public void updateDataById(Map<String, Object> mapObj, String index, String type, String id) {

         UpdateRequest updateRequest = new UpdateRequest();

         updateRequest.index(index).type(type).id(id).doc(mapObj);

         ActionFuture<UpdateResponse> update = client.update(updateRequest);

         if(!"OK".equals(update.actionGet().status().toString().toUpperCase())) {
             throw new RuntimeException("更新数据失败");
         }
     }

         /**
    * 通过ID获取数据
    *
    * @param index  索引,类似数据库
    * @param type   类型,类似表
    * @param id     数据ID
    * @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
    * @return
    */
     public Map<String, Object> searchDataById(String index, String type, String id, String fields) {

         GetRequestBuilder getRequestBuilder = client.prepareGet(index, type, id);

         if (StringUtils.isNotEmpty(fields)) {
                 getRequestBuilder.setFetchSource(fields.split(","), null);
             }

         GetResponse getResponse = getRequestBuilder.execute().actionGet();

         return getResponse.getSource();
     }

         /**
    * 使用分词查询
    *
    * @param index          索引名称
    * @param type           类型名称,可传入多个type逗号分隔
    * @param query          查询条件
    * @param size           文档大小限制
    * @param fields         需要显示的字段,逗号分隔(缺省为全部字段)
    * @param sortField      排序字段
    * @param highlightField 高亮字段
    * @return
    */
     public List<Map<String, Object>> searchListData(String index, String type, QueryBuilder query, Integer size, String fields, String sortField, String highlightField) {
         SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index);
         if (StringUtils.isNotEmpty(type)) {
                 searchRequestBuilder.setTypes(type.split(","));
             }

         if (StringUtils.isNotEmpty(highlightField)) {
                 HighlightBuilder highlightBuilder = new HighlightBuilder();
                 // 设置高亮字段
                 highlightBuilder.field(highlightField);
                 searchRequestBuilder.highlighter(highlightBuilder);
             }

         searchRequestBuilder.setQuery(query);

         if (StringUtils.isNotEmpty(fields)) {
                 searchRequestBuilder.setFetchSource(fields.split(","), null);
             }
         searchRequestBuilder.setFetchSource(true);

         if (StringUtils.isNotEmpty(sortField)) {
                 searchRequestBuilder.addSort(sortField, SortOrder.DESC);
             }

         if (size != null && size > 0 ) {
                 searchRequestBuilder.setSize(size);
             }

         //打印的内容 可以在 Elasticsearch head 和 Kibana  上执行查询

         SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();

         long totalHits = searchResponse.getHits().totalHits;
         long length = searchResponse.getHits().getHits().length;

         if (searchResponse.status().getStatus() == 200 ) {
                 // 解析对象
                 return setSearchResponse(searchResponse, highlightField);
             }
         return null;

     }


         /**
    * 高亮结果集 特殊处理
    *
    * @param searchResponse
    * @param highlightField
    */
     private List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {
         List<Map<String, Object>> sourceList = new ArrayList<Map<String, Object>>();
         StringBuffer stringBuffer = new StringBuffer();

         for (SearchHit searchHit : searchResponse.getHits().getHits()) {
                 searchHit.getSourceAsMap().put("id", searchHit.getId());

                 if (StringUtils.isNotEmpty(highlightField)) {

//                         System.out.println("遍历 高亮结果集,覆盖 正常结果集" + searchHit.getSourceAsMap());
                         Text[] text = searchHit.getHighlightFields().get(highlightField).getFragments();

                         if (text != null) {
                                 for (Text str : text) {
                                         stringBuffer.append(str.string());
                                     }
                                 //遍历 高亮结果集,覆盖 正常结果集
                                 searchHit.getSourceAsMap().put(highlightField, stringBuffer.toString());
                             }
                     }
                 sourceList.add(searchHit.getSourceAsMap());
             }
         return sourceList;
     }
}

5.测试

实体类和mapper懒得放上来了,只要把article和mapper换成对应的操作就行,拿的是之前社团的接口做的测试....

使用之前要在启动类bean注入esutil

sevice层

@Service
@Transactional
public class TestEsServiceImpl implements TestEsService {
    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ESUtil esUtil;

    @Override
    public void createIndex(String index) {
        esUtil.createIndex(index);
    }

    @Override
    public void deleteIndex(String index) {
        esUtil.deleteIndex(index);
    }

    @Override
    public Result addDataBySql(String id) {
        Example example = new Example(Article.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("id", id);
        Article article = articleMapper.selectByExample(example).get(0);
        if(article!=null){
             Map<String, Object> dataMap=new HashMap<String, Object>();
             dataMap.put("id",article.getId());
             dataMap.put("title",article.getTitle());
             dataMap.put("createtime",article.getCreatetime());
             dataMap.put("hearts",article.getHearts());
             esUtil.addData(dataMap,"article","game",id);
             return Result.ok();
        }else{
             return Result.not_ok("不存在该文章数据");
        }
    }

    @Override
    public Result addAllData(String index) {
        List<Article> articlesList = articleMapper.selectAll();
        if(articlesList.size()>0){
             for (Article article : articlesList) {
                     Map<String , Object> mapObj=esUtil.objectTurnMap(article);
                     esUtil.addData(mapObj,index,"game",article.getId());
             }
        }
        return Result.ok();
    }

    @Override
    public Result deleteDataById(String id) {
        esUtil.deleteDataById("article", "game", id);
        return Result.ok();
    }

    /**
       QueryBuilder:定义了查询条件(是全部查询 还是模糊查询 还是分页查询。。。。)
        size:所要查询出的条数
        field:所查询的字段(如果查询所有就直接写null)
        sortField:id,age...(根据字段进行排序,如果不需要设置则传null)
        highlightField:把搜索关键字进行高亮显示(如果不需要则传null)
     **/
    @Override
    public List<Map<String, Object>> selectAll() {
        //1、创建QueryBuilder对象(BoolQueryBuilder是Builder的实现类)
        BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery();
        //2、创建所要搜索到额条件(查询所有数据)
        MatchAllQueryBuilder matchAllQueryBuilder= QueryBuilders.matchAllQuery();
        //3、把搜索的条件放入到BoolQueryBuilder中
        BoolQueryBuilder must = boolQueryBuilder.must(matchAllQueryBuilder);
        //4、返回
        return esUtil.searchListData("article","game",must,100,null,null,null);
    }

    @Override
    public Map<String, Object> selectOneById(String id) {
        return esUtil.searchDataById("article","game",id,null);
    }

    @Override
    public List<Map<String, Object>> selectLikeAll(String title) {
        //1、创建QueryBuilder对象
         BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
         //2、创建查询条件
         //  matchPhraseQuery有两个参数:
             //name:字段名字
             //text:所需要模糊匹配的值(也就是SQL语句中like后面所匹配的值)
        //        MatchPhraseQueryBuilder matchPhraseQueryBuilder=QueryBuilders.matchPhraseQuery("username","zhang");
         MatchPhraseQueryBuilder matchPhraseQueryBuilder=QueryBuilders.matchPhraseQuery("title",title);
         //3、把查询条件放到BoolQueryBuilder对象中
         BoolQueryBuilder must=boolQueryBuilder.must(matchPhraseQueryBuilder);
         return esUtil.searchListData("article","game",must,10,null,null,"title");

    }

controller层:

@RestController
@RequestMapping("/es")
public class TestEsController {

    @Autowired
    private TestEsService testEsService;


    @PostMapping("/createIndex/{index}")
    public Result createIndex(@PathVariable String index) {
        testEsService.createIndex(index);
        return Result.ok();
    }

    @DeleteMapping("/deleteIndex/{index}")
    public Result deleteIndex(@PathVariable String index) {
        testEsService.deleteIndex(index);
        return Result.ok();
    }

    @PostMapping("/data")
    public Result addData() {
        testEsService.addData();
        return Result.ok();
    }

    @PostMapping("/data/{articleId}")
    public Result addDataBySql(@PathVariable String articleId) {
        testEsService.addDataBySql(articleId);
        return Result.ok();
    }

    @PostMapping("/data/all/{index}")
    public Result addAllArticleToIndex(@PathVariable String index) {
        testEsService.addAllData(index);
        return Result.ok();
    }

    @DeleteMapping("/delete/{articleId}")
    public Result deleteDataById(@PathVariable String articleId) {
        testEsService.deleteDataById(articleId);
        return Result.ok();
    }

  
    @GetMapping("/select")
    public Result selectAll() {
        List<Map<String, Object>> maps = testEsService.selectAll();
        return Result.ok(maps);
    }

    @GetMapping("/select/{articleId}")
    public Result selectByOne(@PathVariable String articleId) {
        Map<String, Object> map = testEsService.selectOneById(articleId);
        return Result.ok(map);
    }

    @GetMapping("/select/like/{title}")
    public Result selectLike(@PathVariable String title) {
        List<Map<String, Object>> maps = testEsService.selectLikeAll(title);
        return Result.ok(maps);
    }
}

最后在postman测试

先创建索引,我之前已经创建过了..

加入数据

搜索文章.

 

待优化的问题

1.es 7.x已经移除了type,封装esutil的工具包依旧有用type,待更新

2. es依赖的包中提供的TransportClient,将在未来es 8.x移除

3.可采用springboot提供的es简便方式

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

类似Jpa的操作,和封装es提供的接口,各有利弊....

参考了无数大佬的文章,才终于爬出一个个坑.....

end.

 

 

 


 
发布了6 篇原创文章 · 获赞 0 · 访问量 1457
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章