Spring Boot 技术探索

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".

32、Spring Boot之ElasticSearch的使用

平台环境:

名称

版本号

Mac OS X

10.15.1

JDK

1.8.0_201

Apache Maven

3.6.0

IntelliJ IDEA

2019.3 (Ultimate Edition)

Spring Boot

2.2.2.RELEASE

ElasticSearch

7.5.0 full

  什么是ElasticSearch?

  Elasticsearch是一个开源的分布式RESTful搜索和分析引擎,能够解决越来越多不同的应用场景。

  与关系型数据库概念的不同:

关系型数据库

Elasticsearch

Databases(数据库)

Indices(索引)

Tables(表)

Types(类型)

Rows(行)

Documents(文档)

Columns(列)

Fields(字段)

  到目前为止,ES有4种客户端,分别是:Jest client、Rest client、Transport client、Node client,下面就来说说各个客户端的区别,以及优劣势。

ES支持两种协议  

  • HTTP协议,支持的客户端有Jest client和Rest client
  • Native Elasticsearch binary协议,也就是Transport client和Node client

Jest client和Rest client区别

      Jest client非官方支持,在ES5.0之前官方提供的客户端只有Transport client、Node client。在5.0之后官方发布Rest client,并大力推荐

Transport client和Node client区别

       Transport client(7.0弃用,8.0将被移除)和Node client(2.3弃用)区别:最早的两个客户端,Transport client是不需要单独一个节点。Node client需要单独建立一个节点,连接该节点进行操作,ES2.3之前有独立的API,ES2.3之后弃用该API,推荐用户创建一个节点,并用Transport client连接进行操作。

综合:以上就是各个客户端现在的基本情况,可以看出Rest client目前是官方推荐的,但是Spring Data Elasticsearch默认使用的依然是Transport client与Node client,这可能和ES更新速度有关。

在Spring Data Elasticsearch的jar包中,我们可以看到TransportClientFactoryBean与NodeClientFactoryBean。

因此在使用Spring Data Elasticsearch操作ES时要注意版本匹配,以下是各个版本之间的对照关系表。

Spring Data Release Train

Spring Data Elasticsearch

Elasticsearch

Spring Boot

Moore

3.2.x

6.8.4

2.2.x

Lovelace

3.1.x

6.2.2

2.1.x

Kay

3.0.x

5.5.0

2.0.x

Ingalls

2.1.x

2.4.0

1.5.x

 

ElasticSearch的安装(先看完,再操作)

brew tap elastic/tap

 

brew install elastic/tap/elasticsearch-full

 

安装过程

wangdeMacBook-Pro:~ wang$ brew install elastic/tap/elasticsearch-full
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 4 taps (homebrew/cask, homebrew/services, mongodb/brew and pivotal/tap).
==> Updated Formulae
pivotal/tap/gemfire@9.8                  pivotal/tap/pivnet-cli

==> Tapping elastic/tap
Cloning into '/usr/local/Homebrew/Library/Taps/elastic/homebrew-tap'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 24 (delta 10), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (24/24), done.
Tapped 18 formulae (68 files, 116.9KB).
==> Installing elasticsearch-full from elastic/tap
==> Downloading https://artifacts.elastic.co/downloads/elasticsearch/elasticsearc
######################################################################## 100.0%
==> codesign -f -s - /usr/local/Cellar/elasticsearch-full/7.5.0/libexec/modules/x
==> Caveats
Data:    /usr/local/var/lib/elasticsearch/elasticsearch_wang/
Logs:    /usr/local/var/log/elasticsearch/elasticsearch_wang.log
Plugins: /usr/local/var/elasticsearch/plugins/
Config:  /usr/local/etc/elasticsearch/

To have launchd start elastic/tap/elasticsearch-full now and restart at login:
  brew services start elastic/tap/elasticsearch-full
Or, if you don't want/need a background service you can just run:
  elasticsearch
==> Summary
  /usr/local/Cellar/elasticsearch-full/7.5.0: 921 files, 451.1MB, built in 2 minutes 57 seconds

 

安装完成之后各个路径

Type

Description

Default Location

Setting

home

Elasticsearch home directory or $ES_HOME

/usr/local/var/homebrew/linked/elasticsearch-full

 

conf

Configuration files including elasticsearch.yml

/usr/local/etc/elasticsearch

ES_PATH_CONF

data

The location of the data files of each index / shard allocated on the node. Can hold multiple locations.

/usr/local/var/lib/elasticsearch

path.data

logs

Log files location.

/usr/local/var/log/elasticsearch

path.logs

plugins

Plugin files location. Each plugin will be contained in a subdirectory.

/usr/local/var/homebrew/linked/elasticsearch/plugins

 

启动

brew services start elastic/tap/elasticsearch-full

 

停止

brew services stop elastic/tap/elasticsearch-full

 

查看运行状态

ps aux | grep -v grep | grep elasticsearch-full

 

但是,这里发现brew默认安装版本号过高(7.5版本),而Spring Data Elasticsearch最高支持的版本是6.8.4。在文章后边将会介绍用其他方式访问最新版本ElasticSearch的方法。

 

所以此时希望寻找6.8.4的tar包下载安装,但是这个下载链接无法打开https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.8.4-darwin-x86_64.tar.gz,再次放弃。

再次经过百度,了解到通过git命令获取elasticsearch-full.rb文件的历史版本

信息,还原到旧版elasticsearch-full.rb之后再通过brew本地安装的方法,发现Elasticsearch7版本之后才有的brew安装方法,再次放弃。

 

最后,成功在Docker容器中安装了6.8.4版本。

wangdeMacBook-Pro:/ wang$ docker pull docker.elastic.co/elasticsearch/elasticsearch:6.8.4
6.8.4: Pulling from elasticsearch/elasticsearch
b38629870fdb: Pull complete 
29f2acfe16cc: Pull complete 
356887c30e3e: Pull complete 
70ba61247da5: Pull complete 
aee755e22800: Pull complete 
a46ad139a3d8: Pull complete 
34c154a4459a: Pull complete 
Digest: sha256:f26d2945f1798567e1e63297e3c55ebade0b3202211f23276a7c815a8e496f2d
Status: Downloaded newer image for docker.elastic.co/elasticsearch/elasticsearch:6.8.4
docker.elastic.co/elasticsearch/elasticsearch:6.8.4

 

run命令

docker run --name Elasticsearch -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.8.4

 

运行之后,开始设置

继续输入命令

screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

 

在打开的窗口中粘贴以下命令,回车

sysctl -w vm.max_map_count=262144

 

启动

docker start Elasticsearch

 

停止

docker stop Elasticsearch

 

重启

docker restart Elasticsearch

 

命令解释:The vm.max_map_count kernel setting needs to be set to at least 262144 for production use. Depending on your platform。

 

现在可以打开浏览器访问ElasticSearch的监听端口,如果安装启动正常则会显示出版本信息。

http://localhost:9200

{
  "name" : "FjoKC4I",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "Dt7dnuCQR2K8nHLtTfNjFQ",
  "version" : {
    "number" : "6.8.4",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "bca0c8d",
    "build_date" : "2019-10-16T06:19:49.319352Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.2",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

 

检查ElasticSearch集群运行状态

curl http://127.0.0.1:9200/_cat/health

 

好,服务端到此总算准备好了,接下来开始准备客户端。


Spring Data Elasticsearch方式

这种方式包含两种操作ES的方法ElasticsearchRepository与ElasticsearchTemplate,将在一个Demo中展示。

ElasticsearchRepository的使用方法与Spring Data JPA的方法非常相似。

 

实现的接口:

 

pom.xml

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


   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
         <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
         </exclusion>
      </exclusions>
   </dependency>
</dependencies>

 

application.properties

#cluster-name要和http://localhost:9200中显示的cluster_name值一致
spring.data.elasticsearch.cluster-name=docker-cluster
spring.data.elasticsearch.cluster-nodes=localhost:9300

 

新建Model类Customer

package com.example.demo.model;


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


// @Document注解会对实体中的所有属性建立索引
// indexName = "customer" 表示创建一个名称为 "customer" 的索引
// type = "customer" 表示在索引中创建一个名为 "customer" 的 type
// shards = 1 表示只使用一个分片
// replicas = 0 表示不使用复制
// refreshInterval = "-1" 表示禁用索引刷新
@Document(indexName = "customer", type = "customer", shards = 1, replicas = 0, refreshInterval = "-1")
public class Customer
{
    // Id注解加上后,在Elasticsearch里相应于该列就是主键了,在查询时就可以直接用主键查询
    @Id
    private String id;


    private String userName;


    private String address;


    private int age;


    public Customer()
    {
    }


   public Customer(String userName, String address, int age)
   {
      this.userName = userName;
      this.address = address;
      this.age = age;
   }


    public String getId()
    {
        return this.id;
    }


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


    public String getUserName()
    {
        return userName;
    }


    public void setUserName(String userName)
    {
        this.userName = userName;
    }


    public String getAddress()
    {
        return address;
    }


    public void setAddress(String address)
    {
        this.address = address;
    }


    public int getAge()
    {
        return age;
    }


    public void setAge(int age)
    {
        this.age = age;
    }


    @Override
    public String toString()
    {
        return "Customer{id='" + id + "', userName='" + userName + "', address='" + address + "', age=" + age + "}";
    }
}

 

新建Repository类CustomerRepository

package com.example.demo.repository;


import com.example.demo.model.Customer;
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 CustomerRepository extends ElasticsearchRepository<Customer, String>
{
    public List<Customer> findByAddress(String address);


    public Customer findByUserName(String userName);


    public int deleteByUserName(String userName);


    public Page<Customer> findByAddress(String address, Pageable pageable);
}

 

到此ElasticsearchRepository方式配置完成,接下来开始测试。

新建测试类CustomerRepositoryTest

package com.example.demo;


import com.example.demo.model.Customer;
import com.example.demo.repository.CustomerRepository;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSum;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
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.ResultsExtractor;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;


import java.util.Map;




@SpringBootTest
public class CustomerRepositoryTest
{
    @Autowired
    private CustomerRepository repository;


    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;


    @Test
    public void saveCustomers()
    {
        // 新增
        repository.save(new Customer("Alice", "北京", 13));
        repository.save(new Customer("Bob", "北京", 23));
        repository.save(new Customer("wang", "石家庄", 30));
        repository.save(new Customer("summer", "上海", 22));
    }


    @Test
    public void fetchAllCustomers()
    {
        // 查询
        System.out.println("Customers found with findAll():");
        System.out.println("-------------------------------");
        Iterable<Customer> iterable = repository.findAll();
        for (Customer customer : iterable)
        {
            System.out.println(customer);
        }
    }


    @Test
    public void updateCustomers()
    {
        // 更新
        Customer customer = repository.findByUserName("summer");
        customer.setAddress("北京市海淀区");
        repository.save(customer);
    }


    @Test
    public void fetchIndividualCustomers()
    {
        // 按条件查询
        System.out.println("repository.findByUserName(\"summer\"):");
        System.out.println("--------------------------------");
        System.out.println(repository.findByUserName("summer"));
    }


    @Test
    public void fetchIndividualCustomers2()
    {
        // 按条件查询2
        System.out.println("Customers found with findByAddress(\"北京\"):");
        System.out.println("--------------------------------");
        String q = "北京";
        for (Customer customer : repository.findByAddress(q))
        {
            System.out.println(customer);
        }
    }


    @Test
    public void fetchPageCustomers()
    {
        // 使用Spring Data提供的Pageable分页查询
        System.out.println("使用Spring Data提供的Pageable分页查询:");
        System.out.println("-------------------------------");
        Sort sort = Sort.by(Sort.Direction.DESC, "address.keyword");
        Pageable pageable = PageRequest.of(0, 2, sort);
        Page<Customer> pages = repository.findByAddress("北京", pageable);
        System.out.println("Page customers " + pages.getContent().toString());
    }


    @Test
    public void fetchPageCustomers2()
    {
        // 使用ES提供的QueryBuilder构建复杂条件并带分页的查询
        // 查询条件可以是must(等同于AND)、mustNot(等同于NOT)、should(等同于OR)
        // 注意should不能与must同时使用
        System.out.println("使用ES提供的QueryBuilder构建复杂条件并带分页的查询:");
        System.out.println("-------------------------------");
        QueryBuilder customerQuery = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("address", "北京"));
        Page<Customer> pages = repository.search(customerQuery, PageRequest.of(0, 2));
        System.out.println("Page customers " + pages.getContent().toString());
        pages = repository.search(customerQuery, PageRequest.of(1, 2));
        System.out.println("Page customers " + pages.getContent().toString());
    }


    @Test
    public void fetchShouldNoPage()
    {
        // 使用ES提供的QueryBuilder构建复杂条件查询
        System.out.println("使用ES提供的QueryBuilder构建复杂条件查询:");
        System.out.println("-------------------------------");
        QueryBuilder customerQuery = QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("address", "北京")).should(QueryBuilders.matchQuery("userName", "wang"));
        Iterable<Customer> iterable = repository.search(customerQuery);
        for (Customer customer : iterable)
        {
            System.out.println(customer.toString());
        }
    }


    @Test
    public void fetchAggregation()
    {
        // 聚合查询
        System.out.println("Customers found with fetchAggregation:");
        System.out.println("-------------------------------");


        // 使用QueryBuilder构建查询条件
        QueryBuilder customerQuery = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("address", "北京"));


        // 使用SumAggregationBuilder指明需要聚合的字段
        SumAggregationBuilder sumBuilder = AggregationBuilders.sum("sumAge").field("age");


        // 把前两部分的内容为参数构建成SearchQuery
        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(customerQuery).addAggregation(sumBuilder).build();


        // 把合并之后的SearchQuery作为参数传给ElasticsearchTemplate查询
        Aggregations aggregations = elasticsearchTemplate.query(searchQuery, new ResultsExtractor<Aggregations>()
        {
            @Override
            public Aggregations extract(SearchResponse response)
            {
                return response.getAggregations();
            }
        });


        // 解析聚合查询结果
        // 转换成map集合
        Map<String, Aggregation> aggregationMap = aggregations.asMap();


        // 获得对应的聚合函数的聚合子类,该聚合子类也是个map集合,里面的value就是桶Bucket,我们要获得Bucket
        InternalSum sumAge = (InternalSum) aggregationMap.get("sumAge");
        System.out.println("sum age is " + sumAge.getValue());
    }


    @Test
    public void deleteCustomers()
    {
        // 删除
        repository.deleteAll();
        //repository.deleteByUserName("wang");
    }
}

 

执行

saveCustomers()

fetchAllCustomers()

Customers found with findAll():
-------------------------------
Customer{id='oXoIF28BzoGSr66ynbnT', userName='Alice', address='北京', age=13}
Customer{id='onoIF28BzoGSr66ynrkn', userName='Bob', address='北京', age=23}
Customer{id='o3oIF28BzoGSr66ynrlP', userName='wang', address='石家庄', age=30}
Customer{id='pHoIF28BzoGSr66ynrlz', userName='summer', address='上海', age=22}

 

执行

updateCustomers()

fetchIndividualCustomers()

repository.findByUserName("summer"):
--------------------------------
Customer{id='pHoIF28BzoGSr66ynrlz', userName='summer', address='北京市海淀区', age=22}

 

执行

fetchIndividualCustomers2()

Customers found with findByAddress("北京"):
--------------------------------
Customer{id='oXoIF28BzoGSr66ynbnT', userName='Alice', address='北京', age=13}
Customer{id='onoIF28BzoGSr66ynrkn', userName='Bob', address='北京', age=23}
Customer{id='pHoIF28BzoGSr66ynrlz', userName='summer', address='北京市海淀区', age=22}

 

执行

fetchPageCustomers()

使用Spring Data提供的Pageable分页查询:
-------------------------------
Page customers [Customer{id='pHoIF28BzoGSr66ynrlz', userName='summer', address='北京市海淀区', age=22}, Customer{id='oXoIF28BzoGSr66ynbnT', userName='Alice', address='北京', age=13}]

 

执行

fetchPageCustomers2()

使用ES提供的QueryBuilder构建复杂条件并带分页的查询:
-------------------------------
Page customers [Customer{id='oXoIF28BzoGSr66ynbnT', userName='Alice', address='北京', age=13}, Customer{id='onoIF28BzoGSr66ynrkn', userName='Bob', address='北京', age=23}]
Page customers [Customer{id='pHoIF28BzoGSr66ynrlz', userName='summer', address='北京市海淀区', age=22}]

 

执行

fetchShouldNoPage()

使用ES提供的QueryBuilder构建复杂条件查询:
-------------------------------
Customer{id='p3ovF28BzoGSr66y-Ll0', userName='wang', address='石家庄', age=30}
Customer{id='pXovF28BzoGSr66y-LkM', userName='Alice', address='北京', age=13}
Customer{id='pnovF28BzoGSr66y-LlM', userName='Bob', address='北京', age=23}
Customer{id='qHovF28BzoGSr66y-LmS', userName='summer', address='北京市海淀区', age=22}

 

执行

fetchAggregation()

Customers found with fetchAggregation:
-------------------------------
sum age is 58.0

 

执行

deleteCustomers()

fetchAllCustomers()

Customers found with findAll():
-------------------------------

 

相关文档

精确查询

单个匹配:

// 不分词查询 参数1: 字段名,参数2:字段查询值,因为不分词,所以汉字只能查询一个字,英语是一个单词
QueryBuilder queryBuilder=QueryBuilders.termQuery("fieldName", "fieldlValue");
// 分词查询,采用默认的分词器
QueryBuilder queryBuilder2 = QueryBuilders.matchQuery("fieldName", "fieldlValue");

 

多个匹配:

// 不分词查询,参数1:字段名,参数2:多个字段查询值,因为不分词,因此汉字只能查询一个字,英语是一个单词
QueryBuilder queryBuilder=QueryBuilders.termsQuery("fieldName", "fieldlValue1","fieldlValue2...");
//分词查询,采用默认的分词器
QueryBuilder queryBuilder= QueryBuilders.multiMatchQuery("fieldlValue", "fieldName1", "fieldName2", "fieldName3");
// 匹配所有文件,相当于就没有设置查询条件
QueryBuilder queryBuilder=QueryBuilders.matchAllQuery();

 

模糊查询

模糊查询常见的 5 个方法如下:

//1.常用的字符串查询
QueryBuilders.queryStringQuery("fieldValue").field("fieldName");//左右模糊
//2.常用的用于推荐相似内容的查询
QueryBuilders.moreLikeThisQuery(new String[] {"fieldName"}).addLikeText("pipeidhua");//如果不指定filedName,则默认全部,常用在相似内容的推荐上
//3.前缀查询,如果字段没分词,就匹配整个字段前缀
QueryBuilders.prefixQuery("fieldName","fieldValue");
//4.fuzzy query:分词模糊查询,通过增加 fuzziness 模糊属性来查询,如能够匹配 hotelName 为 tel 前或后加一个字母的文档,fuzziness 的含义是检索的 term 前后增加或减少 n 个单词的匹配查询
QueryBuilders.fuzzyQuery("hotelName", "tel").fuzziness(Fuzziness.ONE);
//5.wildcard query:通配符查询,支持* 任意字符串;?任意一个字符
QueryBuilders.wildcardQuery("fieldName","ctr*");//前面是fieldname,后面是带匹配字符的字符串
QueryBuilders.wildcardQuery("fieldName","c?r?");

 

范围查询

//闭区间查询
QueryBuilder queryBuilder0 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2");
//开区间查询
QueryBuilder queryBuilder1 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2").includeUpper(false).includeLower(false);//默认是 true,也就是包含
//大于
QueryBuilder queryBuilder2 = QueryBuilders.rangeQuery("fieldName").gt("fieldValue");
//大于等于
QueryBuilder queryBuilder3 = QueryBuilders.rangeQuery("fieldName").gte("fieldValue");
//小于
QueryBuilder queryBuilder4 = QueryBuilders.rangeQuery("fieldName").lt("fieldValue");
//小于等于
QueryBuilder queryBuilder5 = QueryBuilders.rangeQuery("fieldName").lte("fieldValue");

 

多条件查询

QueryBuilders.boolQuery()
QueryBuilders.boolQuery().must();//文档必须完全匹配条件,相当于 and
QueryBuilders.boolQuery().mustNot();//文档必须不匹配条件,相当于 not

 


High Level REST Client方式

High Level REST Client,是目前ElasticSearch官方推荐的客户端访问方式。

 

如果之前运行过Docker中的ES,需要先停止。

docker stop Elasticsearch

 

启动Brew安装的最新版本ES

brew services start elastic/tap/elasticsearch-full

 

启动成功之后,访问9200端口测试

http://localhost:9200

{
  "name" : "wangdeMacBook-Pro.local",
  "cluster_name" : "elasticsearch_wang",
  "cluster_uuid" : "-fOY0yKPQui9gcOgjvGnqw",
  "version" : {
    "number" : "7.5.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "e9ccaed468e2fac2275a3761849cbee64b39519f",
    "build_date" : "2019-11-26T01:06:52.518245Z",
    "build_snapshot" : false,
    "lucene_version" : "8.3.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

 

先回忆一下之前RESTful交互的规矩:

请求方式

URI

用途

GET

/Blogs

获取blog列表

POST

/Blog

发布一条blog

PUT

/Blog

修改一条blog

PATCH

/Blog/Content

修改一条blog的内容

GET

/Blog/{id}

获取一条blog

DELETE

/Blog/{id}

删除一条blog

 

新建项目springBootDemo32B

pom.xml

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

   <!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
   <dependency>
      <groupId>org.elasticsearch</groupId>
      <artifactId>elasticsearch</artifactId>
      <version>7.5.0</version>
   </dependency>

   <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-client -->
   <dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>elasticsearch-rest-client</artifactId>
      <version>7.5.0</version>
   </dependency>

   <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client -->
   <dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>elasticsearch-rest-high-level-client</artifactId>
      <version>7.5.0</version>
   </dependency>

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
         <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
         </exclusion>
      </exclusions>
   </dependency>
</dependencies>

 

application.properties

# 这里直接配置到9200端口,省去了很多配置信息
spring.elasticsearch.rest.uris=http://127.0.0.1:9200

 

到此配置就完成了。接下来开始测试。

新建测试类RestHighTest

package com.example.demo;


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.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchPhrasePrefixQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;


@SpringBootTest
public class RestHighTest
{
    @Autowired
    private RestHighLevelClient restHighLevelClient;


    @Test
    public void add()
    {
        Map<String, Object> map = new HashMap<>();
        map.put("id", "20190909");
        map.put("name", "测试");
        map.put("age", 22);
        try
        {
            IndexRequest indexRequest = new IndexRequest("content", "doc", map.get("id").toString()).source(map);
            IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(indexResponse.toString());
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    @Test
    public void search()
    {
        SearchRequest searchRequest = new SearchRequest().indices("content").types("doc");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        MatchPhrasePrefixQueryBuilder mppqb = QueryBuilders.matchPhrasePrefixQuery("name", "测试");
        sourceBuilder.query(mppqb);
        try
        {
            SearchResponse sr = this.restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            String result = sr.toString();
            System.out.println(result);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    @Test
    public void update()
    {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", "20190909");
        map.put("name", "测试-update");
        map.put("age", 22);
        try
        {
            UpdateRequest request = new UpdateRequest("content", "doc", map.get("id").toString()).doc(map);
            UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);
            System.out.println(updateResponse.toString());
        } catch (Exception e)
        {


        }
    }


    @Test
    public void get()
    {
        try
        {
            GetRequest request = new GetRequest("content", "doc", "20190909");
            GetResponse getResponse = this.restHighLevelClient.get(request, RequestOptions.DEFAULT);
            System.out.println(getResponse.toString());
        } catch (Exception e)
        {


        }
    }


    @Test
    public void delete()
    {
        try
        {
            DeleteRequest request = new DeleteRequest("content", "doc", "20190909");
            DeleteResponse deleteResponse = this.restHighLevelClient.delete(request, RequestOptions.DEFAULT);
            System.out.println(deleteResponse.toString());
        } catch (Exception e)
        {


        }
    }
}

 


Low Level REST Client方式

pom.xml

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

    <!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.5.0</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-client -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>7.5.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

 

application.properties

# 这里直接配置到9200端口,省去了很多配置信息
spring.elasticsearch.rest.uris=http://127.0.0.1:9200

到此配置就完成了。接下来开始测试。

新建测试类RestLowTest

package com.example.demo;


import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;


import javax.annotation.Resource;


@SpringBootTest
public class RestLowTest
{
    @Resource
    private RestClient client;


    @Test
    public void add()
    {
        try
        {
            Request request = new Request("PUT", "/content/doc/20190909");
            String jsonString = "{\"id\":\"20190909\",\"name\":\"测试\",\"age\":22}";
            HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
            request.setEntity(entity);
            Response response = client.performRequest(request);
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
        } catch (Exception e)
        {


        }
    }


    @Test
    public void search()
    {
        try
        {
            Request request = new Request("GET", "/content/_search");
            String jsonString = "{\"query\":{\"match\":{\"name\":\"测试\"}}}";
            HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
            request.setEntity(entity);
            Response response = client.performRequest(request);
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }


    @Test
    public void update()
    {
        try
        {
            Request request = new Request("PUT", "/content/doc/20190909");
            String jsonString = "{\"id\":\"20190909\",\"name\":\"测试-update\",\"age\":22}";
            HttpEntity entity = new NStringEntity(jsonString, ContentType.APPLICATION_JSON);
            request.setEntity(entity);
            Response response = client.performRequest(request);
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
        } catch (Exception e)
        {


        }
    }


    @Test
    public void get()
    {
        try
        {
            Request request = new Request("GET", "/content/doc/20190909");
            Response response = client.performRequest(request);
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
        } catch (Exception e)
        {


        }
    }


    @Test
    public void delete()
    {
        try
        {
            Request request = new Request("DELETE", "/content/doc/20190909");
            Response response = client.performRequest(request);
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
        } catch (Exception e)
        {


        }
    }
}

 

参考资料

https://www.jianshu.com/p/aadb54eac0a8

https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html

https://www.elastic.co/guide/en/elasticsearch/reference/6.8/docker.html

https://docs.spring.io/spring-data/elasticsearch/docs/3.2.3.RELEASE/reference/html/#reference

https://blog.csdn.net/qq_25012687/article/details/101050412

https://docs.spring.io/spring-data/elasticsearch/docs/3.2.3.RELEASE/api/

https://gitbook.cn/gitchat/column/5b86228ce15aa17d68b5b55a/topic/5c1af2f31e59245d4d2af6f2

 

ES相关设置资料

You now have a test Elasticsearch environment set up. Before you start serious development or go into production with Elasticsearch, you must do some additional setup:

  • Learn how to configure Elasticsearch.

  • Configure important Elasticsearch settings.

  • Configure important system settings.

 

 

Bootstrap Thumbnail Second
MySQL

MySQL is the world's most popular open source database.

GO

Bootstrap Thumbnail Third
算法基础

本书介绍了什么是计算机算法,如何描述它们,以及如何来评估它们。

GO