高级客户端

Java REST Client 有两种风格:

  • Java Low Level REST Client :用于Elasticsearch的官方低级客户端。它允许通过HTTP与Elasticsearch集群通信。将请求编排和响应反编排留给用户自己处理。它兼容所有的Elasticsearch版本。(PS:学过WebService的话,对编排与反

    编排这个概念应该不陌生。可以理解为对请求参数的封装,以及对响应结果的解析)

  • Java High Level REST Client :用于Elasticsearch的官方高级客户端。它是基于低级客户端的,它提供很多API,并负责请求的编排与响应的反编排。(PS:就好比是,一个是传自己拼接好的字符串,并且自己解析返回的结果;而另一个

    是传对象,返回的结果也已经封装好了,直接是对象,更加规范了参数的名称以及格式,更加面对对象一点)

在 Elasticsearch 7.0 中不建议使用TransportClient,并且在8.0中会完全删除TransportClient。因此,官方更建议我们用Java High Level REST Client。

Java 高级客户端的官方文档位置:http://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

搭建环境

  • 创建项目 elasticsearch-demo

  • 导入pom文件

    <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.3.6.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
     </properties>
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId> 
         </dependency>
 ​
 ​
         <!--引入es的坐标-->
         <dependency>
             <groupId>org.elasticsearch.client</groupId>
             <artifactId>elasticsearch-rest-high-level-client</artifactId>
             <version>7.8.0</version>
         </dependency>
         <dependency>
             <groupId>org.elasticsearch.client</groupId>
             <artifactId>elasticsearch-rest-client</artifactId>
             <version>7.8.0</version>
         </dependency>
         <dependency>
             <groupId>org.elasticsearch</groupId>
             <artifactId>elasticsearch</artifactId>
             <version>7.8.0</version>
         </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
             <version>1.2.4</version>
         </dependency>
     </dependencies>
  • 在 resource 文件夹下面创建 application.yml 文件

     elasticsearch:
       host: 127.0.0.1
       port: 9200
  • 创建启动类

 package com.atguigu;
 ​
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 ​
 @SpringBootApplication
 public class ElasticsearchDemoApplication {
     public static void main(String[] args) {
         SpringApplication.run(ElasticsearchDemoApplication.class, args);
     }
 }
  • 创建 com.atguigu.config.ElasticSearchConfig

 package com.atguigu.config;
 ​
 import org.apache.http.HttpHost;
 import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 ​
 @Configuration
 @ConfigurationProperties(prefix = "elasticsearch")
 public class ElasticSearchConfig {
     private String host;
     private int port;
 ​
     public String getHost() {
         return host;
     }
     public void setHost(String host) {
         this.host = host;
     }
     public int getPort() {
         return port;
     }
     public void setPort(int port) {
         this.port = port;
     }
     @Bean
     public RestHighLevelClient client(){
         return new RestHighLevelClient(RestClient.builder(new HttpHost(host,port,"http")));
     }
 }
  • 新建测试类

 package com.atguigu.test;
 ​
 import org.apache.http.HttpHost;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
 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.support.master.AcknowledgedResponse;
 import org.elasticsearch.client.*;
 import org.elasticsearch.client.indices.CreateIndexRequest;
 import org.elasticsearch.client.indices.CreateIndexResponse;
 import org.elasticsearch.client.indices.GetIndexRequest;
 import org.elasticsearch.client.indices.GetIndexResponse;
 import org.elasticsearch.cluster.metadata.MappingMetaData;
 import org.elasticsearch.common.xcontent.XContentType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 ​
 @SpringBootTest
 public class ElasticsearchTest {
     @Autowired
     private RestHighLevelClient client;
     @Test
     public void contextLoads() {
         System.out.println(client);
 }
 }

索引操作

  • 创建索引

 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class ElasticsearchTest {
     @Autowired
     private RestHighLevelClient client;
     /** 添加索引  */
     @Test
     public void addIndex() throws Exception {
         //1.使用client获取操作索引的对象
         IndicesClient indicesClient = client.indices();
         //2.具体操作,获取返回值
         CreateIndexRequest createRequest = new CreateIndexRequest("abc");
         CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);
         //3.根据返回值判断结果
         System.out.println(response.isAcknowledged());
     }
 }
  • 添加索引和映射

kibana

 PUT aaa/_mapping
 {
   "properties":{
     "address":{
       "type":"text",
       "analyzer":"ik_max_word"
     },
     "age":{
       "type":"long"
     },
     "name":{
       "type":"keyword"
     }
   }
 }
 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class ElasticsearchTest {
     @Autowired
     private RestHighLevelClient client;
     /**添加索引带映射 */
     @Test
     public void addIndexAndMapping() throws IOException {
         //1.使用client获取操作索引的对象
         IndicesClient indicesClient = client.indices();
         //2.具体操作,获取返回值
         CreateIndexRequest createRequest = new CreateIndexRequest("aaa");
         //2.1 设置mappings
         String mapping = "{\n" +
                 "      \"properties\" : {\n" +
                 "        \"address\" : {\n" +
                 "          \"type\" : \"text\",\n" +
                 "          \"analyzer\" : \"ik_max_word\"\n" +
                 "        },\n" +
                 "        \"age\" : {\n" +
                 "          \"type\" : \"long\"\n" +
                 "        },\n" +
                 "        \"name\" : {\n" +
                 "          \"type\" : \"keyword\"\n" +
                 "        }\n" +
                 "      }\n" +
                 "    }";
         createRequest.mapping(mapping,XContentType.JSON);
         CreateIndexResponse response = indicesClient.create(createRequest, RequestOptions.DEFAULT);
         //3.根据返回值判断结果
         System.out.println(response.isAcknowledged());
     }
 }
  • 判断索引是否存在

 /**
      * 判断索引是否存在
      */
     @Test
     public void existIndex() throws IOException {
         IndicesClient indices = client.indices();
         GetIndexRequest getRequest = new GetIndexRequest("aaa");
         boolean exists = indices.exists(getRequest, RequestOptions.DEFAULT);
         System.out.println(exists);
     }
  • 查询索引

 /**
      * 查询索引
      */
     @Test
     public void queryIndex() throws IOException {
         IndicesClient indices = client.indices();
         GetIndexRequest getReqeust = new GetIndexRequest("aaa");
         GetIndexResponse response = indices.get(getReqeust, RequestOptions.DEFAULT);
         //获取结果
         Map<String, MappingMetaData> mappings = response.getMappings();
         for (String key : mappings.keySet()) {
            System.out.println(key+":" + mappings.get(key).getSourceAsMap());
         }
     }
  • 删除索引

  /**
      * 删除索引
      */
     @Test
     public void deleteIndex() throws IOException {
         IndicesClient indices = client.indices();
         DeleteIndexRequest deleteRequest = new DeleteIndexRequest("abc");
         AcknowledgedResponse response = indices.delete(deleteRequest, RequestOptions.DEFAULT);
         System.out.println(response.isAcknowledged());
     }

文档操作

  • 添加文档,使用map作为数据

     /**
      * 添加文档,使用map作为数据
      */
     @Test
     public void addDoc() throws IOException {
         //数据对象,map
         Map data = new HashMap();
         data.put("address","hf");
         data.put("name","ad");
         data.put("age",18);
 ​
         //1.获取操作文档的对象
         IndexRequest request = new IndexRequest("aaa").id("1").source(data);
         //添加数据,获取结果
         IndexResponse response = client.index(request, RequestOptions.DEFAULT);
 ​
         //打印响应结果
         System.out.println(response.getId());
     }
  • 添加文档,使用对象作为数据

先创建对象类

 public class Person {
     private String id;
     private String name;
     private int age;
     private String address;
     // 设置 set get 和tostring方法
 }   
 /**
 * 添加文档,使用对象作为数据
 */
 @Test
 public void addDoc2() throws IOException {
     //数据对象,javaObject
     Person p = new Person();
     p.setId("2");
     p.setName("hf");
     p.setAge(20);
     p.setAddress("ss");
 ​
     //将对象转为json
     String data = JSON.toJSONString(p);
 ​
     //1.获取操作文档的对象
     IndexRequest request = new IndexRequest("aaa").id(p.getId()).source(data,XContentType.JSON);
     //添加数据,获取结果
     IndexResponse response = client.index(request, RequestOptions.DEFAULT);
 ​
     //打印响应结果
     System.out.println(response.getId());
 }
  • 修改文档

 /**
      * 修改文档:添加文档时,如果id存在则修改,id不存在则添加
      */
 @Test
 public void updateDoc() throws IOException {
     //数据对象,javaObject
     Person p = new Person();
     p.setId("2");
     p.setName("硅谷");
     p.setAge(30);
     p.setAddress("北京昌平区");
 ​
     //将对象转为json
     String data = JSON.toJSONString(p);
 ​
     //1.获取操作文档的对象
     IndexRequest request = new IndexRequest("aaa").id(p.getId()).source(data,XContentType.JSON);
     //添加数据,获取结果
     IndexResponse response = client.index(request, RequestOptions.DEFAULT);
 ​
     //打印响应结果
     System.out.println(response.getId());
 }
  • 根据id查询文档

 /**
 * 根据id查询文档
 */
 @Test
 public void findDocById() throws IOException {
     GetRequest getReqeust = new GetRequest("aaa","1");
     //getReqeust.id("1");
     GetResponse response = client.get(getReqeust, RequestOptions.DEFAULT);
     //获取数据对应的json
     System.out.println(response.getSourceAsString());
 }
  • 根据id删除文档

 /**
 * 根据id删除文档
 */
 @Test
 public void delDoc() throws IOException {
     DeleteRequest deleteRequest = new DeleteRequest("aaa","1");
     DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);
     System.out.println(response.getId());
     System.out.println(response.getResult());
 }
  • 批量操作

Bulk 批量操作是将文档的增删改查一些列操作,通过一次请求全都做完。减少网络传输次数。

这里使用的是person索引,之前创建过,没创建的要创建。

 PUT person/_mapping
 {
   "properties":{
     "address":{
       "type":"text",
       "analyzer":"ik_max_word"
     },
     "age":{
       "type":"long"
     },
     "name":{
       "type":"keyword"
     }
   }
 }

下面java代码对应的kibana

 GET person/_search
 ​
 # 批量操作
 # 1 删除1号记录
 # 2 添加8号记录
 # 3 修改2号记录 名称为二号
 ​
 POST _bulk
 {"delete":{"_index":"person","_id":"1"}}
 {"create":{"_index":"person","_id":"8"}}
 {"name":"8号","age":80,"address":"北京"}
 {"update":{"_index":"person","_id":"2"}}
 {"doc":{"name":"2号"}}
 /**
      * 1. 批量操作 bulk
      */
 @Test
 public void testBulk() throws IOException {
     //创建bulkrequest对象,整合所有操作
     BulkRequest bulkRequest = new BulkRequest();
 ​
     /*
         1. 删除1号记录
         2. 添加6号记录
         3. 修改3号记录 名称为 “三号”
          */
     //添加对应操作
     //1. 删除1号记录
     DeleteRequest deleteRequest = new DeleteRequest("person","1");
     bulkRequest.add(deleteRequest);
 ​
     //2. 添加6号记录
     Map map = new HashMap();
     map.put("name","六号");
     IndexRequest indexRequest = new IndexRequest("person").id("6").source(map);
     bulkRequest.add(indexRequest);
 ​
     Map map2 = new HashMap();
     map2.put("name","三号");
     //3. 修改3号记录 名称为 “三号”
     UpdateRequest updateReqeust = new UpdateRequest("person","3").doc(map2);
     bulkRequest.add(updateReqeust);
 ​
     //执行批量操作
     BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
     RestStatus status = response.status();
     System.out.println(status);
 }

批量导入MySQL到ES

将数据库中Goods表的数据导入到ElasticSearch中,自己的表也可以的。

① 创建Goods表并导入数据

· title:商品标题

· price:商品价格

· createTime:创建时间

· categoryName:分类名称。如:家电,手机

· brandName:品牌名称。如:华为,小米

· spec: 商品规格。如: spec:{“屏幕尺寸”,“5寸”,“内存大小”,“128G”}

· saleNum:销量

· stock:库存量

② 创建索引

 PUT goods
 {
     "mappings": {
         "properties": {
             "title": {
                 "type": "text",
                 "analyzer": "ik_smart"
             },
             "price": { 
                 "type": "double"
             },
             "createTime": {
                 "type": "date"
             },
             "categoryName": {   
                 "type": "keyword"
             },
             "brandName": {  
                 "type": "keyword"
             },  
             "spec": {       
                 "type": "object"
             },
             "saleNum": {    
                 "type": "integer"
             },          
             "stock": {  
                 "type": "integer"
             }
         }
     }
 }
 ​
 # 查询索引
 GET goods
  • 添加文档数据

使用kibana操作

 POST goods/_doc/1
 {
   "title":"小米手机",
   "price":1000,
   "createTime":"2019-12-01",
   "categoryName":"手机",
   "brandName":"小米",
   "saleNum":3000,
   "stock":10000,
   "spec":{
     "网络制式":"移动4G",
     "屏幕尺寸":"4.5"
   }
 }
 ​
 # 查询文档数据
 GET goods/_search

java

  • 添加mybatis mysql依赖

 <!--mybatis-->
 <dependency>
     <groupId>org.mybatis.spring.boot</groupId>
     <artifactId>mybatis-spring-boot-starter</artifactId>
     <version>2.1.0</version>
 </dependency>
 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
 </dependency>
  • 添加 application.yml 配置文件

 # datasource
 spring:
   datasource:
     url: jdbc:mysql:///es?serverTimezone=UTC
     username: root
     password: root
     driver-class-name: com.mysql.cj.jdbc.Driver
 ​
 # mybatis
 mybatis:
   mapper-locations: classpath:/mapper/*Mapper.xml
   type-aliases-package: com.jiao.domain
  • 添加 javabean

 public class Goods {
     private int id;
     private String title;
     private double price;
     private int stock;
     private int saleNum;
     private Date createTime;
     private String categoryName;
     private String brandName;
     private Map spec; //将数据库中的json串解析成map进行数据封装
    // @JSONField(serialize = false)//在转换JSON时,忽略该字段
     private String specStr;//接收数据库的信息 "{\"机身内存\":\"16G\",\"网络\":\"联通3G\"}"
     // 生成set  get  和 toString方法
 }    
  • 创建 dao

 @Mapper
 public interface GoodsMapper {
     public List<Goods> findAll();
 }
  • 在 resource 文件夹下面 创建 mapper/GoodsMapper.xml 配置文件

 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.jiao.mapper.GoodsMapper">
     <select id="findAll" resultType="goods">
         select
               `id`,
               `title`,
               `price`,
               `stock`,
               `saleNum`,
               `createTime`,
               `categoryName`,
               `brandName`,
               `spec`  as specStr
          from goods
     </select>
 </mapper>
  • 添加测试方法

 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class ElasticsearchTest2 {
 ​
     @Autowired
     private GoodsMapper goodsMapper;
 ​
     @Autowired
     private RestHighLevelClient client;
 ​
     /**
      * 批量导入
      */
     @Test
     public void importData() throws IOException {
         //1.查询所有数据,mysql
         List<Goods> goodsList = goodsMapper.findAll();
 ​
         //System.out.println(goodsList.size());
         //2.bulk导入
         BulkRequest bulkRequest = new BulkRequest();
 ​
         //2.1 循环goodsList,创建IndexRequest添加数据
         for (Goods goods : goodsList) {
             //2.2 设置spec规格信息 Map的数据   specStr:{}
             //goods.setSpec(JSON.parseObject(goods.getSpecStr(),Map.class));
 ​
             String specStr = goods.getSpecStr();
             //将json格式字符串转为Map集合
             Map map = JSON.parseObject(specStr, Map.class);
             //设置spec map
             goods.setSpec(map);
             //将goods对象转换为json字符串
             String data = JSON.toJSONString(goods);//bean --> {}
             IndexRequest indexRequest = new IndexRequest("goods");
             indexRequest.id(goods.getId()+"").source(data, XContentType.JSON);
             bulkRequest.add(indexRequest);
         }
 ​
         BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
         System.out.println(response.status());
     }
 }

查询操作

  • 查询所有(matchAll查询)

matchAll查询:查询所有文档

kibana

 # 查询
 GET goods/_search
 {
   "query": {
     "match_all": {}
   },
   "from": 0,
   "size": 100
 }
 /**
      * 查询所有
      *  1. matchAll
      *  2. 将查询结果封装为Goods对象,装载到List中
      *  3. 分页。默认显示10条
      */
 @Test
 public void testMatchAll() throws IOException {
     //2. 构建查询请求对象,指定查询的索引名称
     SearchRequest searchRequest = new SearchRequest("goods");
     //4. 创建查询条件构建器SearchSourceBuilder
     SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 ​
     //6. 查询条件
     QueryBuilder query = QueryBuilders.matchAllQuery();//查询所有文档
     //5. 指定查询条件
     sourceBuilder.query(query);
 ​
     //3. 添加查询条件构建器 SearchSourceBuilder
     searchRequest.source(sourceBuilder);
 ​
     // 8. 添加分页信息
     sourceBuilder.from(0);
     sourceBuilder.size(100);
 ​
     //1. 查询,获取查询结果
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     //7. 获取命中对象 SearchHits
     SearchHits searchHits = searchResponse.getHits();
     //7.1 获取总记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     //7.2 获取Hits数据  数组
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         //获取json字符串格式的数据
         String sourceAsString = hit.getSourceAsString();
         //转为java对象
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }  
  • term查询

term查询:不会对查询条件进行分词。

 GET goods
 ​
 # term 查询
 GET goods/_search
 {
   "query": {
     "term": {
       "categoryName": {
         "value": "手机"
       }
     }
   }
 }
 /**
      * termQuery:词条查询
      */
 @Test
 public void testTermQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
 ​
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
 ​
     QueryBuilder query = QueryBuilders.termQuery("title","华为");//term词条查询
     sourceBulider.query(query);
 ​
     searchRequest.source(sourceBulider);
 ​
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
         //转为java
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }  
  • 模糊查询

wildcard查询:会对查询条件进行分词。还可以使用通配符 ?(任意单个字符) 和 * (0个或多个字符)

prefix查询:前缀查询

 # wildcard 查询。查询条件分词,模糊查询 华为,华,*华*
 GET goods/_search
 {
   "query": {
     "wildcard": {
       "title": {
         "value": "华*" 
       }
     }
   }
 }
 ​
 # 前缀查询
 GET goods/_search
 {
   "query": {
     "prefix": {
       "brandName": {
         "value": "三"
       }
     }
   }
 }
 /**
      * 模糊查询:WildcardQuery
      */
 @Test
 public void testWildcardQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
     WildcardQueryBuilder query = QueryBuilders.wildcardQuery("title", "华*");
     sourceBulider.query(query);
     searchRequest.source(sourceBulider);
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
     //转为java
     Goods goods = JSON.parseObject(sourceAsString, Goods.class);
     goodsList.add(goods);
     }
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }
 /**
 * 模糊查询:perfixQuery
 */
 @Test
 public void testPrefixQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
     PrefixQueryBuilder query = QueryBuilders.prefixQuery("brandName", "三");
     sourceBulider.query(query);
     searchRequest.source(sourceBulider);
 ​
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
     //转为java
     Goods goods = JSON.parseObject(sourceAsString, Goods.class);
     goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }
  • 范围查询

range 范围查询:查找指定字段在指定范围内包含值

 # 范围查询 gte 大于等于 lte小于等于
 GET goods/_search
 {
   "query": {
     "range": {
       "price": {
         "gte": 2000,
         "lte": 3000
       }
     }
   }
 }
 ​
 # 范围查询 gte 大于等于 lte小于等于
 GET goods/_search
 {
   "query": {
     "range": {
       "price": {
         "gte": 2000,
         "lte": 3000
       }
     }
   },
   "sort": [
     {
       "price": {
         "order": "desc"
       }
     }
   ]
 }
 /**
      * 1. 范围查询:rangeQuery
      * 2. 排序
      */
 @Test
 public void testRangeQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
     //范围查询
     RangeQueryBuilder query = QueryBuilders.rangeQuery("price");
 ​
     //指定下限 gte大于等于
     query.gte(2000);
     //指定上限 小于等于
     query.lte(3000);
 ​
     sourceBulider.query(query);
 ​
     //排序
     sourceBulider.sort("price", SortOrder.DESC);
     searchRequest.source(sourceBulider);
 ​
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
         //转为java
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         goodsList.add(goods);
     }
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }
  • queryString查询

queryString:

• 会对查询条件进行分词。 • 然后将分词后的查询条件和词条进行等值匹配 • 默认取并集(OR) • 可以指定多个查询字段

 # queryString
 GET goods/_search
 {
   "query": {
     "query_string": {
       "fields": ["title","categoryName","brandName"],
       "query": "华为手机"
     }
   }
 }
 /**
 * queryString
 */
 @Test
 public void testQueryStringQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
 ​
     //queryString
     QueryStringQueryBuilder query = QueryBuilders.queryStringQuery("华为手机")
         .field("title")
         .field("categoryName")
         .field("brandName")
         .defaultOperator(Operator.AND);
 ​
     sourceBulider.query(query);
     searchRequest.source(sourceBulider);
 ​
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
         //转为java
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }
  • 布尔查询

boolQuery:对多个查询条件连接。连接方式:

• must(and):条件必须成立

• must_not(not):条件必须不成立

• should(or):条件可以成立

• filter:条件必须成立,性能比must高。不会计算得分

 # 计算得分
 GET goods/_search
 {
   "query": {
     "bool": {
       "must": [
         {
           "term": {
             "brandName": {
               "value": "华为"
             }
           }
         }
       ]
     }
   }
 }
 ​
 # 不计算得分
 GET goods/_search
 {
   "query": {
     "bool": {
       "filter": [
         {
           "term": {
             "brandName": {
               "value": "华为"
             }
           }
         }  
       ]
     }
   }
 }
 ​
 # 计算得分 品牌是三星,标题还得电视
 GET goods/_search
 {
   "query": {
     "bool": {
       "must": [
         {
           "term": {
             "brandName": {
               "value": "三星"
             }
           }
         }
       ],
       "filter": {
         "term": {
           "title": "电视"
         }
       }
     }
   }
 }
 /**
      * 布尔查询:boolQuery
      * 1. 查询品牌名称为:华为
      * 2. 查询标题包含:手机
      * 3. 查询价格在:2000-3000
      */
 @Test
 public void testBoolQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
 ​
     //1.构建boolQuery
     BoolQueryBuilder query = QueryBuilders.boolQuery();
 ​
     //2.构建各个查询条件
     //2.1 查询品牌名称为:华为
     QueryBuilder termQuery = QueryBuilders.termQuery("brandName","华为");
     query.must(termQuery);
 ​
     //2.2. 查询标题包含:手机
     QueryBuilder matchQuery = QueryBuilders.matchQuery("title","手机");
     query.filter(matchQuery);
 ​
     //2.3 查询价格在:2000-3000
     QueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
     ((RangeQueryBuilder) rangeQuery).gte(2000);
     ((RangeQueryBuilder) rangeQuery).lte(3000);
     query.filter(rangeQuery);
 ​
     //3.使用boolQuery连接
     sourceBulider.query(query);
     searchRequest.source(sourceBulider);
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
     //转为java
     Goods goods = JSON.parseObject(sourceAsString, Goods.class);
     goodsList.add(goods);
     }
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }
  • 聚合查询

    • 指标聚合:相当于MySQL的聚合函数。max、min、avg、sum等

    • 桶聚合:相当于MySQL的 group by 操作。不要对text类型的数据进行分组,会失败。

 # 查询最贵的华为手机,max_price命名随便取,取一个有意义的名字
 GET goods/_search
 {
   "query": {
     "match": {
       "title": "华为手机"
     }
   },
   "aggs": {
     "max_price":{
       "max": {
         "field": "price"
       }
     }
   }
 }
 ​
 # 桶聚合 分组
 GET goods/_search
 {
   "query": {
     "match": {
       "title": "电视"
     }
   },
   "aggs": {
     "goods_brands": {
       "terms": {
         "field": "brandName",
         "size": 100
       }
     }
   }
 }
 /**
      * 聚合查询:桶聚合,分组查询
      * 1. 查询title包含手机的数据
      * 2. 查询品牌列表
      */
 @Test
 public void testAggQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
     // 1. 查询title包含手机的数据
     MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");
 ​
     sourceBulider.query(query);
     // 2. 查询品牌列表
     /* 参数:
             1. 自定义的名称,将来用于获取数据
             2. 分组的字段
          */
     AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
     sourceBulider.aggregation(agg);
 ​
     searchRequest.source(sourceBulider);
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
         //转为java
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 ​
     // 获取聚合结果
     Aggregations aggregations = searchResponse.getAggregations();
     Map<String, Aggregation> aggregationMap = aggregations.asMap();
 ​
     //System.out.println(aggregationMap);
     Terms goods_brands = (Terms) aggregationMap.get("goods_brands");
     List<? extends Terms.Bucket> buckets = goods_brands.getBuckets();
 ​
     List brands = new ArrayList();
     for (Terms.Bucket bucket : buckets) {
         Object key = bucket.getKey();
         brands.add(key);
     }
 ​
     for (Object brand : brands) {
         System.out.println(brand);
     }
 }
  • 高亮查询

高亮三要素:

• 高亮字段 ​ • 前缀 ​ • 后缀

 GET goods/_search
 {
   "query": {
     "match": {
       "title": "电视"
     }
   },
   "highlight": {
     "fields": {
       "title": {
         "pre_tags": "<font color='red'>",
         "post_tags": "</font>"
       }
     }
   }
 }
 /**
      *
      * 高亮查询:
      *  1. 设置高亮
      *      * 高亮字段
      *      * 前缀
      *      * 后缀
      *  2. 将高亮了的字段数据,替换原有数据
      */
 @Test
 public void testHighLightQuery() throws IOException {
     SearchRequest searchRequest = new SearchRequest("goods");
     SearchSourceBuilder sourceBulider = new SearchSourceBuilder();
 ​
     // 1. 查询title包含手机的数据
     MatchQueryBuilder query = QueryBuilders.matchQuery("title", "手机");
     sourceBulider.query(query);
 ​
     //设置高亮
     HighlightBuilder highlighter = new HighlightBuilder();
     //设置三要素
     highlighter.field("title");
     highlighter.preTags("<font color='red'>");
     highlighter.postTags("</font>");
     sourceBulider.highlighter(highlighter);
 ​
     // 2. 查询品牌列表
     /*
         参数:
             1. 自定义的名称,将来用于获取数据
             2. 分组的字段
          */
     AggregationBuilder agg = AggregationBuilders.terms("goods_brands").field("brandName").size(100);
     sourceBulider.aggregation(agg);
 ​
     searchRequest.source(sourceBulider);
     SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
 ​
     SearchHits searchHits = searchResponse.getHits();
     //获取记录数
     long value = searchHits.getTotalHits().value;
     System.out.println("总记录数:"+value);
 ​
     List<Goods> goodsList = new ArrayList<>();
     SearchHit[] hits = searchHits.getHits();
     for (SearchHit hit : hits) {
         String sourceAsString = hit.getSourceAsString();
         //转为java
         Goods goods = JSON.parseObject(sourceAsString, Goods.class);
         // 获取高亮结果,替换goods中的title
         Map<String, HighlightField> highlightFields = hit.getHighlightFields();
         HighlightField HighlightField = highlightFields.get("title");
         Text[] fragments = HighlightField.fragments();
         //替换
         goods.setTitle(fragments[0].toString());
         goodsList.add(goods);
     }
 ​
     for (Goods goods : goodsList) {
         System.out.println(goods);
     }
 }

Spring Data Elasticsearch

· Spring Data的作用:简化了数据库的增删改查操作

Spring Data Jpa介绍

JPA是一个规范,真正操作数据库的是Hibernate(实现数据库增删改查框架[ORM框架],操作数据库采用的方式是面向对象[不写SQL语句]),而spring data jpa是对jpa的封装,将CRUD的方法封装到指定的方法中,操作的时候,只需要调用方法即可。

Spring Data Jpa的实现过程:

1:定义实体,实体类添加Jpa的注解 @Entity @Table @Cloumn @Id

2:定义接口,接口要继承JpaRepository的接口

3:配置spring容器,applicationContext.xml/SpringApplication.run(T.class,args)

Spring Data ElasticSearch简介

(1)Spring Data介绍

  • Spring Data是一个用于简化数据库、非关系型数据库、索引库访问,并支持云服务的开源框架。

  • 其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。

  • Spring Data可以极大的简化JPA(Elasticsearch jdbc redis…)的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一些常用的功能。

  • Spring Data的官网:http://projects.spring.io/spring-data/

(2)Spring Data Elasticsearch介绍

  • Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 。

  • Spring Data为Elasticsearch项目提供集成搜索引擎。

  • 官方网站:http://projects.spring.io/spring-data-elasticsearch/

Spring Data Elasticsearch入门

搭建工程

(1)搭建工程

创建项目 elasticsearch-springdata-es

(2)pom.xml依赖

 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 ​
     <groupId>com.jiao</groupId>
     <artifactId>elasticsearch-springdata-es</artifactId>
     <version>1.0-SNAPSHOT</version>
 ​
      <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.3.6.RELEASE</version>
     </parent>
 ​
     <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>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
     <build>
         <plugins>
             <!-- java编译插件 -->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.2</version>
                 <configuration>
                     <source>1.8</source>
                     <target>1.8</target>
                     <encoding>UTF-8</encoding>
                 </configuration>
             </plugin>
         </plugins>
     </build>
 </project>

(3) 编写实体类

创建com.jiao.domain.Item,代码如下:

 @Document(indexName = "item",shards = 1, replicas = 1)
 public class Item {
     @Id
     private Long id;
 ​
     @Field(type = FieldType.Text, analyzer = "ik_max_word")
     private String title; //标题
 ​
     @Field(type = FieldType.Keyword)
     private String category;// 分类
 ​
     @Field(type = FieldType.Keyword)
     private String brand; // 品牌
 ​
     @Field(type = FieldType.Double)
     private Double price; // 价格
 ​
     @Field(index = false, type = FieldType.Keyword)
     private String images; // 图片地址
 ​
     public Item() {
     }
 ​
     public Item(Long id, String title, String category, String brand, Double price, String images) {
         this.id = id;
         this.title = title;
         this.category = category;
         this.brand = brand;
         this.price = price;
         this.images = images;
     }
 ​
     //get/set/toString…
 }

映射

Spring Data通过注解来声明字段的映射属性,有下面的三个注解:

@Document 作用在类,标记实体类为文档对象,一般有四个属性

indexName:对应索引库名称 shards:分片数量 replicas:副本数量

@Id 作用在成员变量,标记一个字段作为id主键

@Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:

type:字段类型,取值是枚举:FieldType index:是否索引,布尔类型,默认是true store:是否存储,布尔类型,默认是false analyzer:分词器名称:ik_max_word

(4)配置 application.properties 文件

 # es服务地址
 elasticsearch.host=127.0.0.1
 # es服务端口
 elasticsearch.port=9200
 # 配置日志级别,开启debug日志
 logging.level.com.jiao=debug

(5)配置类

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

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

  • ElasticsearchRestTemplate是spring-data-elasticsearch项目中的一个类,和其他spring项目中的template类似。

  • 在新版的spring-data-elasticsearch中,ElasticsearhRestTemplate代替了原来的ElasticsearchTemplate。原因是ElasticsearchTemplate基于TransportClient,TransportClient即将在8.x以后的版本中移除。所以,我们推荐使用ElasticsearchRestTemplate。

  • ElasticsearchRestTemplate基于RestHighLevelClient客户端的。需要自定义配置类,继承AbstractElasticsearchConfiguration,并实现elasticsearchClient()抽象方法,创建RestHighLevelClient对象。

 @ConfigurationProperties(prefix = "elasticsearch")
 @Configuration
 public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
     private String host ;
     private Integer port ;
  
     //重写父类方法
     @Override
     public RestHighLevelClient elasticsearchClient() {
         RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
         RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
         return restHighLevelClient; 
     }
 }

测试

  • 索引操作

 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class TestSpringBootES {
 ​
     @Autowired
     private ElasticsearchRestTemplate elasticsearchTemplate;
 ​
     @Test
     public void testCreate() {
         // 创建索引,会根据Item类的@Document注解信息来创建
         elasticsearchTemplate.createIndex(Item.class); // Item是上面我们自己创建的一个实体类
         // 配置映射,会根据Item类中的id、Field等字段来自动完成映射
         elasticsearchTemplate.putMapping(Item.class);
     }
 }
  • 增删改操作

Spring Data 的强大之处,就在于你不用写任何DAO处理,自动根据方法名或类的信息进行CRUD操作。只要你定义一个接口,然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。

  • 编写 ItemRepository 可以建立一个bao包存放这个接口

 public interface ItemRepository extends ElasticsearchRepository<Item,Long>{
 }
  • 测试

 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class TestSpringBootES {
 ​
     @Autowired
     private ElasticsearchRestTemplate elasticsearchTemplate;
 ​
     @Autowired
     private ItemRepository itemRepository;
 ​
     
     //增加
     @Test
     public void testAdd() {
         Item item = new Item(1L, "小米手机7", " 手机", "小米", 3499.00, "http://image.leyou.com/13123.jpg");
         itemRepository.save(item);
     }
     
     //修改(id存在就是修改,否则就是插入)
     @Test
     public void testUpdate() {
         Item item = new Item(1L, "小米手机7777", " 手机", "小米", 9499.00, "http://image.leyou.com/13123.jpg");
         itemRepository.save(item);
     }
     
     
     //批量新增
     @Test
     public void indexList() {
         List<Item> list = new ArrayList<>();
         list.add(new Item(2L, "坚果手机R1", " 手机", "锤子", 3699.00, "http://image.leyou.com/123.jpg"));
         list.add(new Item(3L, "华为META10", " 手机", "华为", 4499.00, "http://image.leyou.com/3.jpg"));
         // 接收对象集合,实现批量新增
         itemRepository.saveAll(list);
     }
     
     //删除操作
     @Test
     public void testDelete() {
         itemRepository.deleteById(1L);
     }
     
     //根据id查询
     @Test
     public void testQuery(){
         Optional<Item> optional = itemRepository.findById(2L);
         System.out.println(optional.get());
     }
     
     //查询全部,并按照价格降序排序
     @Test
     public void testFind(){
         // 查询全部,并按照价格降序排序
         Iterable<Item> items = this.itemRepository.findAll(Sort.by(Sort.Direction.DESC, "price"));
         items.forEach(item-> System.out.println(item));
     }
     
     
 }

自定义方法

Spring Data 的另一个强大功能,是根据方法名称自动实现功能。

比如:你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。

当然,方法名称要符合一定的约定:

Keyword

Sample

Elasticsearch Query String

And

findByNameAndPrice

{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Or

findByNameOrPrice

{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}

Is

findByName

{"bool" : {"must" : {"field" : {"name" : "?"}}}}

Not

findByNameNot

{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}

Between

findByPriceBetween

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

LessThanEqual

findByPriceLessThan

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

GreaterThanEqual

findByPriceGreaterThan

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Before

findByPriceBefore

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

After

findByPriceAfter

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Like

findByNameLike

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

StartingWith

findByNameStartingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

EndingWith

findByNameEndingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}

Contains/Containing

findByNameContaining

{"bool" : {"must" : {"field" : {"name" : {"query" : "?","analyze_wildcard" : true}}}}}

In

findByNameIn(Collection<String>names)

{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}

NotIn

findByNameNotIn(Collection<String>names)

{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}

Near

findByStoreNear

Not Supported Yet !

True

findByAvailableTrue

{"bool" : {"must" : {"field" : {"available" : true}}}}

False

findByAvailableFalse

{"bool" : {"must" : {"field" : {"available" : false}}}}

OrderBy

findByAvailableTrueOrderByNameDesc

{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

例如,我们来按照价格区间查询,定义这样的一个方法:

 public interface ItemRepository extends ElasticsearchRepository<Item,Long>{
     List<Item> findByPriceBetween(double price1, double price2);
 }

然后添加一些测试数据:

 ​
 @Test
 public void indexList2() {
     List<Item> list = new ArrayList<>();
     list.add(new Item(1L, "小米手机7", "手机", "小米", 3299.00, "http://image.leyou.com/13123.jpg"));
     list.add(new Item(2L, "坚果手机R1", "手机", "锤子", 3699.00, "http://image.leyou.com/13123.jpg"));
     list.add(new Item(3L, "华为META10", "手机", "华为", 4499.00, "http://image.leyou.com/13123.jpg"));
     list.add(new Item(4L, "小米Mix2S", "手机", "小米", 4299.00, "http://image.leyou.com/13123.jpg"));
     list.add(new Item(5L, "荣耀V10", "手机", "华为", 2799.00, "http://image.leyou.com/13123.jpg"));
     // 接收对象集合,实现批量新增
     itemRepository.saveAll(list);
 }

不需要写实现类,然后我们直接去运行:

 @Test
 public void queryByPriceBetween(){
     List<Item> list = this.itemRepository.findByPriceBetween(2000.00, 3500.00);
     for (Item item : list) {
         System.out.println("item = " + item);
     }
 }

虽然基本查询和自定义方法已经很强大了,但是如果是复杂查询(模糊、通配符、词条查询等)就显得力不从心了。此时,只能使用原生查询。

文章作者: JAT
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Strive
三方技术 ElasticSearch Java ElasticSearch 数据库
喜欢就支持一下吧