SpringBoot集成ElasticSearch

SpringBoot2.0自带集成ElasticSearch最高只支持5.6.10,所以高于5.6.10需要自己导入依赖,此说法来自网上,具体需要验证

pom.xml:

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <hadoop.version>2.7.4</hadoop.version>
        <scala.version>2.11</scala.version>
        <spark.version>2.1.0</spark.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <elasticSearch.version>6.7.1</elasticSearch.version>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!--elasticsearch-->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticSearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>${elasticSearch.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch</groupId>
                    <artifactId>elasticsearch</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticSearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>${elasticSearch.version}</version>
        </dependency>

        <!--spark-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_${scala.version}</artifactId>
            <version>${spark.version}</version>
            <scope>provided</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_${scala.version}</artifactId>
            <version>${spark.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_${scala.version}</artifactId>
            <version>${spark.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_${scala.version}</artifactId>
            <version>${spark.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>6.0.6</version>
        </dependency>
    </dependencies>

org.elasticsearch.client--transport 依赖添加之后,会依赖一系列的插件,客户端等,虽然在springboot2.0中依旧依赖  org.elasticsearch-elasticsearch-6.7.1,但是在依赖列表中,其添加的依赖依然是elasticSearch5.6.10的依赖,所以必须排除这个依赖,手动添加org.elasticsearch-elasticsearch6.7.1的依赖,目前只有这种解决方法,否则导致版本不一致冲突

还导入了一个 elasticsearch-rest-high-level-client的jar,为了使用其他API:https://www.cnblogs.com/ginb/p/8716485.html

目前我只是用了一个本地节点,ElasticSearchConfig:

package com.cn.ypp.elasticsearch;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;

@Configuration
public class ElasticSearchConfig {

    private Logger logger  = LoggerFactory.getLogger(this.getClass());

    @Value("${elasticsearch.ip}")
    private String ip;
    @Value("${elasticsearch.port}")
    private String port;
    @Value("${elasticsearch.clusterName}")
    private String clusterName;

    @Bean
    public TransportClient getTransportClient() {

        logger.info("ElasticSearch初始化开始。。");
        logger.info("要连接的节点的ip是{},端口是{},集群名为{}" , ip , port , clusterName);
        TransportClient transportClient = null;
        try {
            Settings settings = Settings.builder()
                    //集群名称
                    .put("cluster.name",clusterName)
                    //目的是为了可以找到集群,嗅探机制开启
                    .put("client.transport.sniff",true)
                    .build();
            transportClient = new PreBuiltTransportClient(settings);
            TransportAddress es = new TransportAddress(InetAddress.getByName(ip),Integer.parseInt(port));
            transportClient.addTransportAddress(es);
            logger.info("ElasticSearch初始化完成。。");
        }catch (Exception e){
            e.printStackTrace();
            logger.error("ElasticSearch初始化失败:" +  e.getMessage(),e);
        }
        return transportClient;
    }
}
如果是集群,像下面这样:
package com.cn.ypp.elasticsearch;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;

@Configuration
public class ElasticSearchConfig {

    private Logger logger  = LoggerFactory.getLogger(this.getClass());

    @Value("${elasticsearch.firstIp}")
    private String firstIp;
    @Value("${elasticsearch.secondIp}")
    private String secondIp;
    @Value("${elasticsearch.thirdIp}")
    private String thirdIp;
    @Value("${elasticsearch.firstPort}")
    private String firstPort;
    @Value("${elasticsearch.secondPort}")
    private String secondPort;
    @Value("${elasticsearch.thirdPort}")
    private String thirdPort;
    @Value("${elasticsearch.clusterName}")
    private String clusterName;

    @Bean
    public TransportClient getTransportClient() {

        logger.info("ElasticSearch初始化开始。。");
        logger.info("要连接的节点1的ip是{},端口是{},集群名为{}" , firstIp , firstPort , clusterName);
        logger.info("要连接的节点2的ip是{},端口是{},集群名为{}" , secondIp , secondPort , clusterName);
        logger.info("要连接的节点3的ip是{},端口是{},集群名为{}" , thirdIp , thirdPort , clusterName);
        TransportClient transportClient = null;
        try {
            Settings settings = Settings.builder()
                    //集群名称
                    .put("cluster.name",clusterName)
                    //目的是为了可以找到集群,嗅探机制开启
                    .put("client.transport.sniff",true)
                    .build();
            transportClient = new PreBuiltTransportClient(settings);
            TransportAddress firstAddress = new TransportAddress(InetAddress.getByName(firstIp),Integer.parseInt(firstPort));
            TransportAddress secondAddress = new TransportAddress(InetAddress.getByName(secondIp),Integer.parseInt(secondPort));
            TransportAddress thirdAddress = new TransportAddress(InetAddress.getByName(thirdIp),Integer.parseInt(thirdPort));
            transportClient.addTransportAddress(firstAddress);
            transportClient.addTransportAddress(secondAddress);
            transportClient.addTransportAddress(thirdAddress);
            logger.info("ElasticSearch初始化完成。。");
        }catch (Exception e){
            e.printStackTrace();
            logger.error("ElasticSearch初始化失败:" +  e.getMessage(),e);
        }
        return transportClient;
    }
}

以上的都是网上的说法,所以引入了相关的jar和配置类

 

常用基本操作:

GET _cat/indices?v  查看健康值

SpringBoot集成ElasticSearch

SpringBoot集成ElasticSearch

GET /_cat/nodes?v 获取节点列表

SpringBoot集成ElasticSearch

GET _cat/indices?v  列出所有索引

SpringBoot集成ElasticSearch 目前是空的,没有创建过索引

 

使用java操作索引等:

Elasticsearch JAVA操作有三种客户端:

1、TransportClient

2、JestClient  

3、RestClient

4、spring-boot-starter-data-elasticsearch(有待验证,据说最高只支持elasticsearch2.x版本)

先试一试spring-boot-starter-data-elasticsearch

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

application.yml:

server:
  port: 8054

spark:
  spark-home: .
  app-name: sparkTest
  master: local[4]

# ELASTICSEARCH (ElasticsearchProperties)
# Elasticsearch cluster name.
spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: localhost:9300
      repositories:
        enabled: true

Book:

package com.cn.ypp.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;

@Document(indexName = "book", type = "_doc")
public class Book extends BaseEntity{

    private String title;
    private String author;
    private String postDate;

    public Book(){}

    public Book(String id, String title, String author, String postDate){
        setId(id);
        this.title = title;
        this.author=author;
        this.postDate=postDate;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPostDate() {
        return postDate;
    }

    public void setPostDate(String postDate) {
        this.postDate = postDate;
    }

    @Override
    public String toString() {
        return "book{" +
                "id='" + getId() + '\'' +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", postDate='" + postDate + '\'' +
                '}';
    }
}

  BaseEntity:

package com.cn.ypp.entity;

import org.springframework.data.annotation.Id;

public class BaseEntity {
    @Id
    private String id;

    public String getId() {
        return id;
    }

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

  BookRepository:

package com.cn.ypp.elasticsearch.dao;

import com.cn.ypp.entity.Book;
import org.apache.commons.net.nntp.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

public interface BookRepository extends ElasticsearchRepository<Book,String> {

    Page<Book> findByAuthor(String author, Pageable pageable);

    Page<Book> findByTitle(String title, Pageable pageable);

    List<Book> findByTitle(String title);

}

BookService:

package com.cn.ypp.elasticsearch.service;

import com.cn.ypp.entity.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

import java.util.List;
import java.util.Optional;

public interface BookService {
    Optional<Book> findById(String id);

    Book save(Book blog);

    void delete(Book blog);

    Optional<Book> findOne(String id);

    List<Book> findAll();

    Page<Book> findByAuthor(String author, PageRequest pageRequest);

    Page<Book> findByTitle(String title, PageRequest pageRequest);

    List<Book> findTitle(String titileKeyword);

    Iterable<Book> saveAll(List<Book> books);
}

 BookServiceImpl:

package com.cn.ypp.elasticsearch.service;

import com.cn.ypp.elasticsearch.dao.BookRepository;
import com.cn.ypp.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;


@Service
public class BookServiceImpl implements  BookService {
    
    @Autowired
    private BookRepository bookRepository;

    @Override
    public Optional<Book> findById(String id) {
        //CrudRepository中的方法
        return bookRepository.findById(id);
    }

    @Override
    public Book save(Book blog) {
        return bookRepository.save(blog);
    }

    @Override
    public void delete(Book blog) {
        bookRepository.delete(blog);
    }

    @Override
    public Optional<Book> findOne(String id) {
        return bookRepository.findById(id);
    }

    @Override
    public List<Book> findAll() {
        return (List<Book>) bookRepository.findAll();
    }

    @Override
    public Page<Book> findByAuthor(String author, PageRequest pageRequest) {
        return bookRepository.findByAuthor(author,pageRequest);
    }

    @Override
    public Page<Book> findByTitle(String title, PageRequest pageRequest) {
        return bookRepository.findByTitle(title,pageRequest);
    }

    @Override
    public List<Book> findTitle(String titileKeyword) {
        return bookRepository.findByTitle(titileKeyword);
    }
    @Override
    public Iterable<Book> saveAll(List<Book> books) {
        return bookRepository.saveAll(books);
    }
}

EsController:

package com.cn.ypp.elasticsearch.controller;

import com.cn.ypp.elasticsearch.service.BookService;
import com.cn.ypp.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

@Controller
@RequestMapping("/es")
public class EsController {

    @Autowired
    private BookService bookService;

    @RequestMapping("/book/{id}")
    @ResponseBody
    public Book getBookById(@PathVariable String id){
        Optional<Book> opt =bookService.findById(id);
        Book book=opt.get();
        System.out.println(book);
        return book;
    }

    @RequestMapping("/save")
    @ResponseBody
    public void Save(){
        Book book1=new Book("1","ES入门教程","ypp","2018-10-01");
        Book book2=new Book("2","从ES入门教程到放弃java","ypp","2018-10-01");
        Book book3=new Book("3","mysql从入门到放弃","ypp","2018-10-01");
        Book book4=new Book("4","redis从入门到放弃","ypp","2018-10-01");
        Book book5=new Book("5","spark从入门到放弃","ypp","2018-10-01");
        Book book6=new Book("6","hbase从入门到放弃","ypp","2018-10-01");
        Book book7=new Book("7","zookeeper从入门到放弃","ypp","2018-10-01");
        Book book8=new Book("8","mq从入门到放弃","ypp","2018-10-01");
        Book book9=new Book("9","spring cloud从入门到放弃","ypp","2018-10-01");
        List<Book> books=new ArrayList<>();
        books.add(book1);
        books.add(book2);
        books.add(book3);
        books.add(book4);
        books.add(book5);
        books.add(book6);
        books.add(book7);
        books.add(book8);
        books.add(book9);
        bookService.saveAll(books);
    }

    @RequestMapping("/keyword")
    @ResponseBody
    public List<Book> keyword(@RequestParam("keyword")String keyword){
        return bookService.findTitle(keyword);
    }
}

 发送请求:http://localhost:8054/es/save

查看elasticsearch:

SpringBoot集成ElasticSearch

事实证明是可以的。自己实践才是真理,其他3种方式有时间继续干

有一点说明的是在BookRepository里面有一个方法findByTitle,本身ES顶部等接口都没有方法,也没有实现,是如何查询到的呢?这里不需要实现类,会自动创建实现类,具体如何实现不清楚,对ES来说是个新手,但大概能猜出应该是动态代理(如有错误,请纠错,十分感谢)

还有方法只要符合一定的规则,它就可以自动发现并为你实现,以name字段举例:

And          findByNameAndPwd
Or             findByNameOrSex
Is              findById
Between   findByIdBetween
Like           findByNameLike
NotLike     findByNameNotLike
OrderBy    findByIdOrderByXDesc
Not           findByNameNot

这也就能说明为什么findByTitle能查询到了,结果如下

SpringBoot集成ElasticSearch

我只查询的mysql,它自动实现了英文分词?

如果需要比较复杂的查询,就需要借助ElasticsearchTemplate来进行实现了

EsBookRepository:

package com.cn.ypp.elasticsearch.dao;

import com.cn.ypp.entity.Book;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import java.util.Date;
import java.util.List;

import static org.elasticsearch.index.query.QueryBuilders.*;

public class EsBookRepository {

    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    public List<Book> page() {

        //查询关键字
        String word = "ypp-mysql娃哈哈入门";

        // 分页设置,id倒序
        Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC, "id");

        SearchQuery searchQuery;

        //0.使用queryStringQuery完成单字符串查询queryStringQuery(word, "title")
        //1.multiMatchQuery多个字段匹配 .operator(MatchQueryBuilder.Operator.AND)多项匹配使用and查询即完全匹配都存在才查出来
        //searchQuery = new NativeSearchQueryBuilder().withQuery(multiMatchQuery(word, "title", "content").operator(MatchQueryBuilder.Operator.AND)).withPageable(pageable).build();

        //2.多条件查询:title和author必须包含word=“XXX”且postDate必须小于当前时间以id倒序分页结果
        searchQuery = new NativeSearchQueryBuilder()
                .withQuery(
                        new BoolQueryBuilder().must(multiMatchQuery(word, "title", "author").operator(Operator.AND))
                                .must(rangeQuery("postDate").lt(new Date())
                        )
                )
                .withPageable(pageable)
                .build();

        return elasticsearchTemplate.queryForList(searchQuery, Book.class);
    }

}