【Elasticsearch】整合Spring Data Elasticsearch(二)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 【Elasticsearch】整合Spring Data Elasticsearch

删除索引

删除索引的API:


8cdcfa8607d94042ac0f32320c25871c.png


可以根据类名或索引名删除。


示例:

@Test
public void deleteIndex() {
    esTemplate.deleteIndex("item");
}

新增文档数据

Repository接口

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


来看下Repository的继承关系:


.5a71dbe331bc49b1aed3bf293eb5d24d.png


含Crud的接口表示已经完成增删改查操作,例如:ElasticsearchCrudRepository接口:


81c2281ade3d413cab0d3503f0c9bbe7.png


如果继承ElasticsearchRepository子接口,同时也继承了其父接口声明的所有功能。


所以,我们只需要定义接口,然后继承它就OK了。


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

接下来,我们测试新增数据:


新增一个对象

@Autowired
private ItemRepository itemRepository;
@Test
public void index() {
    Item item = new Item(1L, "小米手机7", "手机",
                         "小米", 3499.00, "http://image.baidu.com/13123.jpg");
    itemRepository.save(item);
}

去页面查询看看:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "item",
        "_type": "docs",
        "_id": "1",
        "_score": 1,
        "_source": {
          "id": 1,
          "title": "小米手机7",
          "category": " 手机",
          "brand": "小米",
          "price": 3499,
          "images": "http://image.baidu.com/13123.jpg"
        }
      }
      }
    ]
  }
}


批量新增

代码:

@Test
public void indexList() {
    List<Item> list = new ArrayList<>();
    list.add(new Item(2L, "坚果手机R1", "手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(3L, "华为META10", "手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
    // 接收对象集合,实现批量新增
    itemRepository.saveAll(list);
}


再次去页面查询:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1,
    "hits": [
      {
        "_index": "item",
        "_type": "docs",
        "_id": "2",
        "_score": 1,
        "_source": {
          "id": 2,
          "title": "坚果手机R1",
          "category": " 手机",
          "brand": "锤子",
          "price": 3699,
          "images": "http://image.baidu.com/13123.jpg"
        }
      },
      {
        "_index": "item",
        "_type": "docs",
        "_id": "3",
        "_score": 1,
        "_source": {
          "id": 3,
          "title": "华为META10",
          "category": " 手机",
          "brand": "华为",
          "price": 4499,
          "images": "http://image.baidu.com/13123.jpg"
        }
      },
      {
        "_index": "item",
        "_type": "docs",
        "_id": "1",
        "_score": 1,
        "_source": {
          "id": 1,
          "title": "小米手机7",
          "category": " 手机",
          "brand": "小米",
          "price": 3499,
          "images": "http://image.baidu.com/13123.jpg"
        }
      }
    ]
  }
}


修改

修改和新增是同一个接口,区分的依据就是id,这一点跟我们在页面发起PUT请求是类似的。


删除

@Test
public void testDelete() {
    itemRepository.deleteById(1L);
}


查询

基本查询

ElasticsearchRepository提供了一些基本的查询方法:


64c6146d048d442d9af18fc23b0a8a81.png


我们来试试查询所有:


@Test
public void query(){
    // 查询全部,并安装价格降序排序
    Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").descending());
    for (Item item : items) {
        System.out.println("item = " + item);
    }
}

64c6146d048d442d9af18fc23b0a8a81.png

结果:

90ed348ecaec4aeeab12e1e1ab64dab5.png


自定义方法

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" : "?"}}}}

image.png

image.png

image.png


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


public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
    /**
     * 根据价格区间查询
     * @param price1
     * @param price2
     * @return
     */
    List<Item> findByPriceBetween(double price1, double price2);
}


然后添加一些测试数据:

@Test
public void indexList() {
    List<Item> list = new ArrayList<>();
    list.add(new Item(1L, "小米手机7", "手机", "小米", 3299.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(2L, "坚果手机R1", "手机", "锤子", 3699.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(3L, "华为META10", "手机", "华为", 4499.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(4L, "小米Mix2S", "手机", "小米", 4299.00, "http://image.baidu.com/13123.jpg"));
    list.add(new Item(5L, "荣耀V10", "手机", "华为", 2799.00, "http://image.baidu.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);
    }
}

结果:


自定义查询

先来看最基本的match query:

@Test
public void search(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米手机"));
    // 搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 总条数
    long total = items.getTotalElements();
    System.out.println("total = " + total);
    for (Item item : items) {
        System.out.println(item);
    }
}


NativeSearchQueryBuilder:Spring提供的一个查询条件构建器,帮助构建json格式的请求体

QueryBuilders.matchQuery("title", "小米手机"):利用QueryBuilders来生成一个查询。QueryBuilders提供了大量的静态方法,用于生成各种不同类型的查询:


507502417ae349e096bc711f1b568195.png


Page:默认是分页查询,因此返回的是一个分页的结果对象,包含属性:

totalElements:总条数

totalPages:总页数

Iterator:迭代器,本身实现了Iterator接口,因此可直接迭代得到当前页的数据

其它属性:


7ad21467aff84936a026817858b60ba8.png


结果:


f5c98e2d69ac4965acea7b3d09b78448.png


练习1:查询标题中含“手机”,且品牌是“小米”的商品列表信息

@Test
public void testQuery2() {
    //1 条件构建器
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    //2 拼凑条件
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    boolQueryBuilder.must(QueryBuilders.matchQuery("title","手机"));
    boolQueryBuilder.must(QueryBuilders.matchQuery("brand","小米"));
    queryBuilder.withQuery(boolQueryBuilder);
    //3 查询
    Page<Item> page = this.itemRepository.search(queryBuilder.build());
    //4 处理结果
    System.out.println(page.getTotalElements());
    page.getContent().forEach(System.out::println);
}

练习2:查询标题中含“手机”,且品牌不是“小米”的商品列表信息

分页查询

利用NativeSearchQueryBuilder可以方便的实现分页:


@Test
public void searchByPage(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
    // 分页:
    int page = 0; //第几页,从0开始
    int size = 2; //每页个数
    queryBuilder.withPageable(PageRequest.of(page,size));
    // 搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 总条数
    long total = items.getTotalElements();
    System.out.println("总条数 = " + total);
    // 总页数
    System.out.println("总页数 = " + items.getTotalPages());
    // 当前页
    System.out.println("当前页:" + items.getNumber());
    // 每页大小
    System.out.println("每页大小:" + items.getSize());
    for (Item item : items) {
        System.out.println(item);
    }
}


结果:


db8239ccada94c128f44686aa3b8ab9b.png


可以发现,Elasticsearch中的分页是从第0页开始。


排序

排序也通用通过NativeSearchQueryBuilder完成:

@Test
public void searchAndSort(){
    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
    // 添加基本分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
    // 排序
    queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
    // 搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    // 总条数
    long total = items.getTotalElements();
    System.out.println("总条数 = " + total);
    for (Item item : items) {
        System.out.println(item);
    }
}

db8239ccada94c128f44686aa3b8ab9b.png

结果:


1cdb43cc298841c4b11e36917f6a73a0.png

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
1月前
|
存储 搜索推荐 Java
|
2月前
|
存储 应用服务中间件 测试技术
Elasticsearch Data Stream 数据流使用
Elasticsearch Data Stream 数据流使用
36 0
|
2月前
|
监控 Java Docker
从零开始,用Docker-compose打造SkyWalking、Elasticsearch和Spring Cloud的完美融合
从零开始,用Docker-compose打造SkyWalking、Elasticsearch和Spring Cloud的完美融合
387 0
|
2天前
|
索引
Elasticsearch exception [type=illegal_argument_exception, reason=index [.1] is the write index for data stream [slowlog] and cannot be deleted]
在 Elasticsearch 中,你尝试删除的索引是一个数据流(data stream)的一部分,而且是数据流的写入索引(write index),因此无法直接删除它。为了解决这个问题,你可以按照以下步骤进行操作:
|
1月前
|
Java 数据库 Spring
如何使用Spring Data JPA完成审计功能
如何使用Spring Data JPA完成审计功能
|
3月前
|
Java 数据库连接 API
Spring Boot整合Spring Data JPA进行CRUD和模糊查询
Spring Boot整合Spring Data JPA进行CRUD和模糊查询
38 0
|
4月前
|
缓存 NoSQL Java
Spring Data Redis对象缓存序列化问题
在使用 Redis 时,有没有遇到同我一样,对象缓存序列化问题的呢?
67 6
Spring Data Redis对象缓存序列化问题
|
4月前
|
存储 Java 数据库连接
Spring Boot 嵌入式服务器、Hibernate 关系和 Spring Data 全解析
Spring Boot 的嵌入式服务器功能是一项方便而强大的功能,它允许你在应用程序中直接运行 Web 服务器,无需将其部署到单独的独立 Web 服务器中。这使得开发、测试和部署 Web 应用程序变得容易,而且它还是轻量级的、易于启动和停止的,易于配置。
65 0
|
6月前
|
缓存 Java Go
解决Spring Data JPA查询存在缓存问题及解决方案
解决Spring Data JPA查询存在缓存问题及解决方案
343 0
|
4月前
|
XML Java 数据库连接
Spring Boot的数据访问之Spring Data JPA以及Hibernate的实战(超详细 附源码)
Spring Boot的数据访问之Spring Data JPA以及Hibernate的实战(超详细 附源码)
47 0

热门文章

最新文章