删除索引
删除索引的API:
可以根据类名或索引名删除。
示例:
@Test public void deleteIndex() { esTemplate.deleteIndex("item"); }
新增文档数据
Repository接口
Spring Data 的强大之处,就在于你不用写任何DAO处理,自动根据方法名或类的信息进行CRUD操作。只要你定义一个接口,然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。
来看下Repository的继承关系:
.
含Crud的接口表示已经完成增删改查操作,例如:ElasticsearchCrudRepository接口:
如果继承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提供了一些基本的查询方法:
我们来试试查询所有:
@Test public void query(){ // 查询全部,并安装价格降序排序 Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").descending()); for (Item item : items) { System.out.println("item = " + 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" : "?"}}}} |
例如,我们来按照价格区间查询,定义这样的一个方法:
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提供了大量的静态方法,用于生成各种不同类型的查询:
Page:默认是分页查询,因此返回的是一个分页的结果对象,包含属性:
totalElements:总条数
totalPages:总页数
Iterator:迭代器,本身实现了Iterator接口,因此可直接迭代得到当前页的数据
其它属性:
结果:
练习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); } }
结果:
可以发现,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); } }
结果: