1. 程式人生 > 其它 >理想國SpringDataElasticSearch入門教程

理想國SpringDataElasticSearch入門教程

技術標籤:Elasticsearch微服務Java

01.Spring Data 簡介

what:是什麼

  • Spring Data是一個用於簡化持久層資料訪問的開源框架。
  • 主要目標是使得對資料的訪問變得方便快捷
  • Spring Data可以極大的簡化資料操作的寫法,可以在幾乎不用寫實現的情況下,實現對資料的訪問和操作。
  • 包括CRUD外,還包括如分頁、排序等一些常用的功能,幾乎可以節省持久層程式碼80%以上的編碼工作量。
  • Spring Data的官網:http://projects.spring.io/spring-data/

02.Spring Data ElasticSearch簡介

what:是什麼

  • Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進行封裝 。
  • Spring Data為Elasticsearch專案提供整合搜尋引擎。
  • Spring Data Elasticsearch POJO的關鍵功能區域為中心的模型與Elastichsearch互動文件和輕鬆地編寫一個儲存庫資料訪問層。
  • 官方網站:http://projects.spring.io/spring-data-elasticsearch/

why:為什麼使用

  • 用來操作ElasticSearch的框架,使得開發更加便捷

03.環境搭建

實現步驟:

  • 建立SpringBoot的專案:版本為<version>2.1.9.RELEASE</version>
  • 勾選starter依賴座標
  • 編寫持久層介面GoodDao,編寫pojo實體類
  • 配置檔案,叢集配置,ElasticSearch服務地址http://127.0.0.1:9300

實現過程:

  • 建立SpringBoot的專案!
  • 勾選starter依賴座標,依賴如下
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.lxgzhw</groupId> <artifactId>springdata_es_demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springdata_es_demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

編寫持久層介面GoodDao,編寫pojo實體類

package com.lxgzhw.dao;

public interface GoodDao {
}

pojo實體類,商品good:這裡的索引名稱不能是已存在的

package com.lxgzhw.pojo;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 商品實體類
 *
 * @Document() 註解作用:定義一個索引庫,一個型別
 * indexName屬性:指定索引庫的名稱
 * type屬性:指定型別名稱
 * shards屬性:指定分片數
 * replicas屬性:指定複製副本數
 */
@Data
@Document(indexName = "lxgzhw1", type = "goods", shards = 5, replicas = 1)
public class Good {
    private Long id;//商品的唯一標識
    private String title;//標題
    private String category;//分類
    private String brand;//品牌
    private Double price;//價格
    private String images;//圖片地址
    //getter,setter,toString
}

配置檔案:applacation.properties

  • 叢集配置,ElasticSearch服務地址http://127.0.0.1:9301
  • 這裡的叢集名稱和服務地址要與之前教程中配置的保持一致
# 配置叢集名稱
spring.data.elasticsearch.cluster-name=my-Elasticsearch
# 配置es的服務地址
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9301

04.建立和刪除索引

幾個用到的註解:

  • @Document:宣告索引庫配置
    • indexName:索引庫名稱
    • type:型別名稱,預設是“docs”
    • shards:分片數量,預設5
    • replicas:副本數量,預設1
  • @Id:宣告實體類的id
  • @Field:宣告欄位屬性
    • type:欄位的資料型別
    • analyzer:指定分詞器型別
    • index:是否建立索引 預設為true
    • store:是否儲存 預設為false

實體類配置:

package com.lxgzhw.pojo;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

/**
 * 商品實體類
 *
 * @Document() 註解作用:定義一個索引庫,一個型別
 * indexName屬性:指定索引庫的名稱
 * type屬性:指定型別名稱
 * shards屬性:指定分片數
 * replicas屬性:指定複製副本數
 */
@Data
@Document(indexName = "lxgzhw2", type = "goods", shards = 5, replicas = 1)
public class Good {
    //必須有id,這裡的id是全域性唯一的標識,等同於es中的“_id”
    @Id
    private Long id;
    /**
     * type: 欄位資料型別
     * analyzer: 分詞器型別
     * index: 是否索引(預設值:true)
     * store: 是否儲存(預設值:false)
     */
    @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(type = FieldType.Keyword, index = false)
    private String images;//圖片地址
    //getter ,setter ,toString
}

測試類:Demo01IndexOperationTests.java

package com.lxgzhw;

import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * 建立索引
 * 配置對映
 * 刪除索引
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo01IndexOperationTests {
    //模板設計模式
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Test
    public void createIndexAndPutMapping() {
        elasticsearchTemplate.createIndex(Good.class);//建立索引
        elasticsearchTemplate.putMapping(Good.class);//配置對映
    }

    //刪除索引
    @Test
    public void deleteIndex() {
        elasticsearchTemplate.deleteIndex(Good.class);
    }

}

05.文件的常見增刪改查

修改GoodDao介面:繼承ElasticsearchRespository模板介面

package com.lxgzhw.dao;

import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface GoodDao extends ElasticsearchRepository<Good, Long> {
}

新增測試類:SpringdataEsGoodCRUDTests.java

package com.lxgzhw;

import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
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.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsGoodCRUDTests {
    //注入Good業務層實現類
    @Autowired
    private GoodDao goodDao;

    /**
     * 新增
     */
    @Test
    public void save() {
        Good good = new Good();
        good.setId(1l);
        good.setTitle("小米手機");
        good.setCategory("手機");
        good.setBrand("小米");
        good.setPrice(19999.0);
        good.setImages("http://image.leyou.com/12479122.jpg");
        goodDao.save(good);
    }

    //修改
    @Test
    public void update() {
        Good good = new Good();
        good.setId(1l);
        good.setTitle("小米手機");
        good.setCategory("手機");
        good.setBrand("小米");
        good.setPrice(9999.0);
        good.setImages("http://image.leyou.com/12479122.jpg");
        goodDao.save(good);
    }

    //刪除
    @Test
    public void delete() {
        Good good = new Good();
        good.setId(1l);
        goodDao.delete(good);
    }

    //根據id查詢
    @Test
    public void findById() {
        Good good = goodDao.findById(1l).get();
        System.out.println(good);
    }

    //查詢所有
    @Test
    public void findAll() {
        Iterable<Good> goods = goodDao.findAll();
        for (Good good : goods) {
            System.out.println(good);
        }
    }

    //批量新增
    @Test
    public void saveAll() {
        List<Good> goodList = new ArrayList<>();
        for (int i = 0; i < 500; i++) {
            Good good = new Good();
            good.setId((long) i);
            good.setTitle("[" + i + "]小米手機");
            good.setCategory("手機");
            good.setBrand("小米");
            good.setPrice(19999.0 + i);
            good.setImages("http://image.leyou.com/12479122.jpg");
            goodList.add(good);
        }
        goodDao.saveAll(goodList);
    }

    //分頁查詢
    @Test
    public void findByPageable() {
        //設定排序(排序方式,正序還是倒序,排序的id)
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        int currentPage = 2;//當前頁
        int pageSize = 100;//每頁顯示多少條
        //設定查詢分頁
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize, sort);
        //分頁查詢
        System.out.println("分頁資料:");
        Page<Good> goodPage = goodDao.findAll(pageRequest);
        for (Good good : goodPage.getContent()) {
            System.out.println(good);
        }
    }
}

07.Search查詢

what:是什麼

  • ElasticSearch的search方法中QueryBuilders,就是第一章中的查詢物件構建物件QueryBuilders。
  • QueryBuilders具備的能力,search方法都具備。
  • 所以,在這裡重複內容不贅述,僅舉例term查詢。

建立測試類:SpringdataEsSearchTests.java

package com.lxgzhw;

import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsSearchTests {
    //注入Good業務層實現類
    @Autowired
    private GoodDao goodDao;

    /**
     * term查詢
     * search(termQueryBuilder) 調用搜索方法,引數查詢構建器物件
     */
    @Test
    public void termQuery() {
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
        Iterable<Good> goods = goodDao.search(termQueryBuilder);
        for (Good g : goods) {
            System.out.println(g);
        }
    }

    /**
     * term查詢加分頁
     */
    @Test
    public void termQueryByPage() {
        int currentPage = 0;
        int pageSize = 5;
        //設定查詢分頁
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize);
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");
        Iterable<Good> goods = goodDao.search(termQueryBuilder, pageRequest);
        for (Good g : goods) {
            System.out.println(g);
        }
    }
}

08.自定義方法名稱查詢

what:是什麼

  • GoodsRepository提供了非常強大的自定義查詢功能;只要遵循SpringData提供的語法,我們可以任意定義方法宣告
  • 查詢語法:findBy+欄位名+Keyword+欄位名+…
KeywordSampleElasticsearch Query String
AndfindByNameAndPrice{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
OrfindByNameOrPrice{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
IsfindByName{"bool" : {"must" : {"field" : {"name" : "?"}}}}
NotfindByNameNot{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
BetweenfindByPriceBetween{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
BeforefindByPriceBefore{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
AfterfindByPriceAfter{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
LikefindByNameLike{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
StartingWithfindByNameStartingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
EndingWithfindByNameEndingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
InfindByNameIn(Collection<String>names){"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
NotInfindByNameNotIn(Collection<String>names){"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
OrderByfindByNameOrderByNameDesc{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"name" : "?"}}}

持久層介面:

package com.lxgzhw.dao;

import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * ElasticsearchRepository 持久層操作ElasticSearch的模板介面
 */
public interface GoodDao extends ElasticsearchRepository<Good, Long> {
    /**
     * 根據title和價格查詢,and的關係
     */
    List<Good> findAllByTitleAndPrice(String title, Double price);

    /**
     * 根據商品價格範圍查詢
     * 最低價格lowPrice
     * 最高價格highPrice
     */
    List<Good> findByPriceBetween(Double lowPrice, Double highPrice);
}

新增測試類:SpringdataEsCustomMethodQueryTests.java

package com.lxgzhw;

import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsCustomMethodQueryTests {
    //注入Good業務層實現類
    @Autowired
    private GoodDao goodDao;

    /**
     * 根據標題及價格查詢
     * 要求價格等於20023且標題的內容包含小米關鍵詞
     */
    @Test
    public void findAllByTitleAndPrice() {
        String title = "小米";
        Double price = 20023.0;
        List<Good> goods = goodDao.findAllByTitleAndPrice(title, price);
        for (Good g : goods) {
            System.out.println(g);
        }
    }

    /**
     * 根據價格範圍查詢
     * 要求商品價格再3000,到20000之間
     */
    @Test
    public void findPriceBetween() {
        double lowPrice = 3000.0;//最低價
        double highPrice = 20000.0;//最高價
        List<Good> goods = goodDao.findByPriceBetween(lowPrice, highPrice);
        for (Good g : goods) {
            System.out.println(g);
        }
    }
}