Spring Data ElasticSearch使用

1. 什麼是Spring Data

Spring Data是一個用於簡化數據庫訪問,並支持雲服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷,並支持map-reduce框架和雲計算數據服務。 Spring Data可以極大的簡化JPA的寫法,可以在幾乎不用寫實現的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。

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

Spring Data常用的功能模塊如下:
在這裏插入圖片描述在這裏插入圖片描述

2. 什麼是Spring Data ElasticSearch

Spring Data Elasticsearch是Spring Data項目下的一個子模塊。

查看 Spring Data的官網:http://projects.spring.io/spring-data/
Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進行封裝 。Spring Data爲Elasticsearch項目提供集成搜索引擎。Spring Data Elasticsearch POJO的關鍵功能區域爲中心的模型與Elastichsearch交互文檔和輕鬆地編寫一個存儲庫數據訪問層。

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

3. Spring Data ElasticSearch入門

1)導入Spring Data ElasticSearch座標

<?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.itheima</groupId>
    <artifactId>itheima_elasticsearch_demo3</artifactId>
    <version>1.0-SNAPSHOT</version>


    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>5.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>5.6.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.24</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.8.1</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
            <version>3.0.5.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch.plugin</groupId>
                    <artifactId>transport-netty4-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.4.RELEASE</version>
        </dependency>

    </dependencies>
    
</project>

2)創建applicationContext.xml配置文件,引入elasticsearch命名空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/data/elasticsearch
		http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
		">
		
</beans>

3)編寫實體Article

package com.bruceliu.bean;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:32
 * @QQ:1241488705
 * @Description:
 */
public class Article {

    private Integer id;
    private String title;
    private String content;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";
    }


}

4)編寫Dao

package com.bruceliu.dao;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:33
 * @QQ:1241488705
 * @Description:
 */
import com.bruceliu.bean.Article;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {

}

5)編寫Service

package com.bruceliu.service;

import com.bruceliu.bean.Article;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
public interface ArticleService {

    public void save(Article article);
}

package com.bruceliu.service.impl;

import com.bruceliu.bean.Article;
import com.bruceliu.dao.ArticleRepository;
import com.bruceliu.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    public void save(Article article) {
        articleRepository.save(article);
    }

}

6) 配置applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
       xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/data/elasticsearch
		http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
		">


    <!-- 掃描Dao包,自動創建實例 -->
    <elasticsearch:repositories base-package="com.bruceliu.dao"/>

    <!-- 掃描Service包,創建Service的實體 -->
    <context:component-scan base-package="com.bruceliu.service"/>

    <!-- 配置elasticSearch的連接 -->
    <!-- 配置elasticSearch的連接 -->
    <elasticsearch:transport-client id="client" cluster-nodes="localhost:9300" cluster-name="my-elasticsearch"/>


    <!-- ElasticSearch模版對象 -->
    <bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
        <constructor-arg name="client" ref="client"></constructor-arg>
    </bean>


</beans>

7)配置實體
基於spring data elasticsearch註解配置索引、映射和實體的關係

package com.bruceliu.bean;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:32
 * @QQ:1241488705
 * @Description:
 */
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 文檔對象 (索引信息、文檔類型 )
@Document(indexName="blog3",type="article")
public class Article {

    //@Id 文檔主鍵 唯一標識
    @Id
    //@Field 每個文檔的字段配置(類型、是否分詞、是否存儲、分詞器 )
    @Field(store=true, index = false,type = FieldType.Integer)
    private Integer id;
    
    @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    private String title;
    
    @Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    private String content;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", content=" + content + "]";
    }

}

其中,註解解釋如下:
@Document(indexName="blob3",type="article"):
    indexName:索引的名稱(必填項)
    type:索引的類型
@Id:主鍵的唯一標識
@Field(index=true,analyzer="ik_smart",store=true,searchAnalyzer="ik_smart",type = FieldType.text)
    index:是否設置分詞
    analyzer:存儲時使用的分詞器
    searchAnalyze:搜索時使用的分詞器
    store:是否存儲
    type: 數據類型

8)創建測試類SpringDataESTest

package com.brueliu.test;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:37
 * @QQ:1241488705
 * @Description:
 */

import com.bruceliu.bean.Article;
import com.bruceliu.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Resource
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 創建索引和映射
     */
    @Test
    public void createIndex() {
        elasticsearchTemplate.createIndex(Article.class);
        elasticsearchTemplate.putMapping(Article.class);
    }

    /**
     * 測試保存文檔
     */
    @Test
    public void saveArticle() {
        Article article = new Article();
        article.setId(100);
        article.setTitle("測試SpringData ElasticSearch");
        article.setContent("Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進行封裝 \n" +
                "    Spring Data爲Elasticsearch Elasticsearch項目提供集成搜索引擎");
        articleService.save(article);
    }
}

在這裏插入圖片描述

4.Spring Data ElasticSearch的常用操作

4.1.增刪改查方法測試

package com.bruceliu.service;

import com.bruceliu.bean.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
public interface ArticleService {

    //刪除
    public void delete(Article article);

    //查詢全部
    public Iterable<Article> findAll();

    //分頁查詢
    public Page<Article> findAll(Pageable pageable);

}

package com.bruceliu.service.impl;

import com.bruceliu.bean.Article;
import com.bruceliu.dao.ArticleRepository;
import com.bruceliu.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

 
    public void delete(Article article) {
        articleRepository.delete(article);
    }

    public Iterable<Article> findAll() {
        Iterable<Article> iter = articleRepository.findAll();
        return iter;
    }

    public Page<Article> findAll(Pageable pageable) {
        return articleRepository.findAll(pageable);
    }


}
package com.brueliu.test;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:37
 * @QQ:1241488705
 * @Description:
 */

import com.bruceliu.bean.Article;
import com.bruceliu.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Resource
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 創建索引和映射
     */
    @Test
    public void createIndex() {
        elasticsearchTemplate.createIndex(Article.class);
        elasticsearchTemplate.putMapping(Article.class);
    }

    /**
     * 測試保存文檔
     */
    @Test
    public void saveArticle() {
        Article article = new Article();
        article.setId(100);
        article.setTitle("測試SpringData ElasticSearch!");
        article.setContent("Spring Data ElasticSearch 基於 spring data API 簡化 elasticSearch操作,將原始操作elasticSearch的客戶端API 進行封裝 \n" +
                "    Spring Data爲Elasticsearch Elasticsearch項目提供集成搜索引擎");
        articleService.save(article);
    }

    /**測試保存*/
    @Test
    public void save(){
        Article article = new Article();
        article.setId(1001);
        article.setTitle("elasticSearch 3.0版本發佈");
        article.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
        articleService.save(article);
    }

    /**測試更新*/
    @Test
    public void update(){
        Article article = new Article();
        article.setId(1001);
        article.setTitle("elasticSearch 3.0版本發佈...更新");
        article.setContent("ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
        articleService.save(article);
    }

    /**測試刪除*/
    @Test
    public void delete(){
        Article article = new Article();
        article.setId(1001);
        articleService.delete(article);
    }

    /**批量插入*/
    @Test
    public void save100(){
        for(int i=1;i<=10;i++){
            Article article = new Article();
            article.setId(i);
            article.setTitle(i+"elasticSearch 3.0版本發佈..,更新");
            article.setContent(i+"ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口");
            articleService.save(article);
        }
    }

    /**分頁查詢*/
    @Test
    public void findAllPage(){
        Pageable pageable = PageRequest.of(1,5);
        Page<Article> page = articleService.findAll(pageable);
        for(Article article:page.getContent()){
            System.out.println(article);
        }
    }

4.2.常用查詢命名規則

關鍵字 命名規則 解釋 示例
and findByField1AndField2 根據Field1和Field2獲得數據 findByTitleAndContent
or findByField1OrField2 根據Field1或Field2獲得數據 findByTitleOrContent
is findByField 根據Field獲得數據 findByTitle
not findByFieldNot 根據Field獲得補集數據 findByTitleNot
between findByFieldBetween 獲得指定範圍的數據 findByPriceBetween
lessThanEqual findByFieldLessThan 獲得小於等於指定值的數據 findByPriceLessThan

4.2.1 查詢方法測試

1)dao層實現

package com.bruceliu.dao;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:33
 * @QQ:1241488705
 * @Description:
 */
import com.bruceliu.bean.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ArticleRepository extends ElasticsearchRepository<Article, Integer> {

    //根據標題查詢
    List<Article> findByTitle(String condition);

    //根據標題查詢(含分頁)
    Page<Article> findByTitle(String condition, Pageable pageable);
}

2)service層實現

package com.bruceliu.service;

import com.bruceliu.bean.Article;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
public interface ArticleService {

    //根據標題查詢
    List<Article> findByTitle(String condition);

    //根據標題查詢(含分頁)
    Page<Article> findByTitle(String condition, Pageable pageable);
}

package com.bruceliu.service.impl;

import com.bruceliu.bean.Article;
import com.bruceliu.dao.ArticleRepository;
import com.bruceliu.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:34
 * @QQ:1241488705
 * @Description:
 */
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    public List<Article> findByTitle(String condition) {
        return articleRepository.findByTitle(condition);
    }

    public Page<Article> findByTitle(String condition, Pageable pageable) {
        return articleRepository.findByTitle(condition,pageable);
    }

}

3)測試代碼

package com.brueliu.test;

/**
 * @Auther: bruceliu
 * @Date: 2019/12/4 16:37
 * @QQ:1241488705
 * @Description:
 */

import com.bruceliu.bean.Article;
import com.bruceliu.service.ArticleService;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataESTest {

    @Autowired
    private ArticleService articleService;

    @Resource
    private TransportClient client;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**條件查詢*/
    @Test
    public void findByTitle(){
        String condition = "版本";
        List<Article> articleList = articleService.findByTitle(condition);
        for(Article article:articleList){
            System.out.println(article);
        }
    }

    /**條件分頁查詢*/
    @Test
    public void findByTitlePage(){
        String condition = "版本";
        Pageable pageable = PageRequest.of(1,5);
        Page<Article> page = articleService.findByTitle(condition,pageable);
        for(Article article:page.getContent()){
            System.out.println(article);
        }
    }

}

4.2.2.使用Elasticsearch的原生查詢對象進行查詢

  @Test
    public void findByNativeQuery() {
        //創建一個SearchQuery對象
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                //設置查詢條件,此處可以使用QueryBuilders創建多種查詢
                .withQuery(QueryBuilders.queryStringQuery("版本").defaultField("title"))
                //還可以設置分頁信息
                .withPageable(PageRequest.of(1, 5))
                //創建SearchQuery對象
                .build();


        //使用模板對象執行查詢
        List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
        for (Article article : articles) {
            System.out.println(article);
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章