Spring Data ElasticSearch(一)

1. Spring Data简介

Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。 Spring Data可以极大的简化JPA的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了CRUD外,还包括如分页、排序等一
些常用的功能。

Spring Data的官网:

http://projects.spring.io/spring-data/

Spring Data常用的功能模块如下:
在这里插入图片描述
在这里插入图片描述

1.2 Spring Data ElasticSearch

Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 。Spring Data为Elasticsearch项目提供集成搜索引擎。Spring Data ElasticsearchPOJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储库数据访问层。

官方网站:

http://projects.spring.io/spring-data-elasticsearch/

2. 简单查询案例

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">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.16.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>SpringData_ElasticSearch</artifactId>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <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>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2)启动器配置文件


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class,args);
    }
}

配置文件

spring:
 data:
  elasticsearch:
   cluster-name: my-elasticsearch
   cluster-nodes: 192.168.45.131:9300

3)编写实体Article

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 = "blog4",type="article")
public class Article {
    @Id
    @Field(type = FieldType.Long, store = true)
    private long id;
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
    private String title;
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
    private String content;

    public long getId() {
        return id;
    }

    public void setId(long 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
方法命名规则查询的基本语法findBy + 属性 + 关键词 + 连接符

关键字命名规则解释示例
andfindByField1AndField2根据Field1和Field2获得数据findByTitleAndContent
orfindByField1OrField2根据Field1或Field2获得数据findByTitleOrContent
isfindByField根据Field获得数据findByTitle
notfindByFieldNot根据Field获得补集数据findByTitleNot
betweenfindByFieldBetween获得指定范围的数据findByPriceBetween
lessThanEqualfindByFieldLessThan获得小于等于指定值的数据findByPriceLessThan
import com.da.domain.Article;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import org.springframework.data.domain.Pageable;
import java.util.List;

public interface ArticelRepository extends ElasticsearchRepository<Article,Long> {
public List<Article> findByTitle(String title);
public List<Article> findByTitleOrContent(String title,String content);
public List<Article> findAllByContent(String content, Pageable pageable);
}

6)创建测试类

import com.da.dao.ArticelRepository;
import com.da.domain.Article;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
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.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;

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

@RunWith(SpringRunner.class)
@SpringBootTest
public class Test {
    @Autowired
    ArticelRepository articelRepository;
    @Autowired
    ElasticsearchTemplate template;

    @org.junit.Test
    public void createIndex() {
        //创建索引并配置映射关系
        template.createIndex(Article.class);
        //配置映射关系
        // template.putMapping(Article.class);
    }

    @org.junit.Test
    public void addDocument() {

        for (int i = 11; i < 20; i++) {
            Article article = new Article();
            article.setId(i);
            article.setTitle("女护士路遇昏迷男子跪地抢救:救人是职责更是本能" + i);
            article.setContent("这是一个美丽的女护士妹妹" + i);
            //把文档写入索引库
            articelRepository.save(article);
        }
    }

    @org.junit.Test
    public void deleteDocumentById() {
        //删除一个
        //articelRepository.deleteById(1L);
        //删除全部
        articelRepository.deleteAll();
    }

    @org.junit.Test
    public void findAll() {
        Iterable<Article> all = articelRepository.findAll();
        all.forEach(a -> System.out.println(a));
    }

    @org.junit.Test
    public void findFindById() {
        Optional<Article> byId = articelRepository.findById(14L);
        Article article = byId.get();
        System.out.println(article);

    }

    @org.junit.Test
    public void findByTitle() {
        List<Article> s = articelRepository.findByTitle("女护士");
        s.stream().forEach(a -> System.out.println(a));

    }

    @org.junit.Test
    public void findByContent() {
        Pageable pageable = PageRequest.of(1, 5);
        System.out.println("------------------");
        List<Article> a = articelRepository.findAllByContent("美丽", pageable);
        a.forEach(a1 -> System.out.println(a1));
    }

    @org.junit.Test
    public void testNativeSearchQuery() {
//创建一个查询对象
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.queryStringQuery("女护士")
                        .defaultField("title")).withPageable(PageRequest.of(0, 15))
                .build();
        //执行查询
        List<Article> list = template.queryForList(query, Article.class);
        list.forEach(a -> System.out.println(a));

    }

}

3. 聚合查询

实体类

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 = "blog4",   type = "car")
public class Car {
    @Id
    @Field(type = FieldType.Long, store = true)
    private Long id;
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
    private String name;
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart", fielddata
            = true)
    private String color;
    @Field(type = FieldType.Text, store = true, analyzer = "ik_smart", fielddata
            = true)
    private String brand;
    @Field(type = FieldType.Double, store = true)
    private Double price;
public Car(){}
    public Car(Long id, String name, String color, String brand, Double price) {
        this.id = id;
        this.name = name;
        this.color = color;
        this.brand = brand;
        this.price = price;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

Dao

import com.da.domain.Car;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface CarRepository extends ElasticsearchRepository<Car,Long> {

}

初始化索引库

import com.da.dao.CarRepository;
import com.da.domain.Car;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
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.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class CarTest {
    @Autowired
    CarRepository carDao;

    @Test
    public void saveCar(){
        carDao.save(new Car(1l, "比亚迪A1", "红色", "比亚迪", 50000d));
        carDao.save(new Car(2l, "比亚迪A2", "白色", "比亚迪", 70000d));
        carDao.save(new Car(3l, "比亚迪A3", "白色", "比亚迪", 80000d));
        carDao.save(new Car(4l, "比亚迪A4", "红色", "比亚迪", 60000d));
        carDao.save(new Car(5l, "比亚迪A5", "红色", "比亚迪", 90000d));
        carDao.save(new Car(6l, "宝马A1", "红色", "宝马", 10000d));
        carDao.save(new Car(7l, "宝马A2", "黑色", "宝马", 20000d));
        carDao.save(new Car(8l, "宝马A3", "黑色", "宝马", 30000d));
        carDao.save(new Car(9l, "宝马A4", "红色", "宝马", 40000d));
        carDao.save(new Car(10l, "宝马A5", "红色", "宝马", 50000d));
        carDao.save(new Car(11l, "奔驰A1", "红色", "奔驰", 10000d));
        carDao.save(new Car(12l, "奔驰A2", "黑色", "奔驰", 20000d));
        carDao.save(new Car(13l, "奔驰A3", "黑色", "奔驰", 30000d));
        carDao.save(new Car(14l, "奔驰A4", "红色", "奔驰", 40000d));
        carDao.save(new Car(15l, "奔驰A5", "红色", "奔驰", 50000d));

    }
   }

划分桶

GET /car_index/car/_search
{
"query": {
"bool": {
"should": [
{
"match_all": {}
}
]
}
},
"aggs": {
"group_by_bland": {
"terms": {
"field": "color"
}
}
}
}

桶内度量

GET /car_index/car/_search
{
"query": {
"bool": {
"should": [
{
"match_all": {}
}
]
}
},
"aggs": {
"group_by_bland": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}

Spring Data ElasticSearch代码实现

1.划分桶

@Test
    public void testQuerySelfAggs(){
        //查询条件的构造器
        NativeSearchQueryBuilder query=new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery());
        //排除所有的字段查询
        query.withSourceFilter(new FetchSourceFilter(new String[]{},null));

        //添加聚合条件
        query.addAggregation(AggregationBuilders.terms("group_by_color").field("color"));
        //执行查询,把查询结果直接转为聚合page
        AggregatedPage<Car> a=(AggregatedPage<Car>)carDao.search(query.build());
        //从所有的聚合中获取对应名称的聚合
        StringTerms terms=(StringTerms) a.getAggregation("group_by_color");
        //从聚合的结果中获取所有的桶信息
        List<StringTerms.Bucket> buckets = terms.getBuckets();
          for(StringTerms.Bucket bucket:buckets){
              String keyAsString = bucket.getKeyAsString();
              long docCount = bucket.getDocCount();
              System.out.println("color:"+keyAsString+"   ======>"+"总数:"+docCount);
          }

    }

2.桶内度量

 @Test
    public void testQuerySelfSubAggs(){
        //查询条件的构造器
        NativeSearchQueryBuilder query=new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery());
        //排除所有的字段查询
        query.withSourceFilter(new FetchSourceFilter(new String[]{},null));
        //添加聚合条件
        query.addAggregation(AggregationBuilders.terms("group_by_color").field("color")
                .subAggregation(AggregationBuilders.avg("avg_price").field("price")));
        //执行查询,把查询结果直接转为聚合page
        AggregatedPage<Car> a=(AggregatedPage<Car>) carDao.search(query.build());
        //从所有的聚合中获取对应名称的聚合
        StringTerms t=(StringTerms)a.getAggregation("group_by_color");
        //从聚合的结果中获取所有的桶信息
        List<StringTerms.Bucket> buckets = t.getBuckets();
        for(StringTerms.Bucket bucket:buckets){
            String keyAsString = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            InternalAvg avg_price =(InternalAvg)bucket.getAggregations().asMap().get("avg_price");
            System.out.println("color:"+keyAsString+"=====>"+"数量:"+docCount+"   ====>avg_price"+avg_price);
        }

    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值