五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条

Spring Data Elasticsearch


https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#reference

Spring Data Elasticsearch 是 Elasticsearch 搜索引擎开发的解决方案。它提供:

模板对象,用于存储、搜索、排序文档和构建聚合的高级API。

案例说明


在 Elasticsearch 中存储学生数据,并对学生数据进行搜索测试。


数据结构:

学号    姓名    性别    出生日期
 27       张三    男       2020-12-4

案例测试以下数据操作:

学号 姓名 性别 出生日期
27 张三 2020-12-4

创建 students 索引和映射
C - 创建学生数据
R - 访问学生数据
U - 修改学生数据
D - 删除学生数据
使用 Repository 和 Criteria 搜索学生数据


 

一  新建spring工程,添加elasticsearch依赖,修改pom版本,以及编辑配置文件

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第1张图片

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第2张图片

spring:
  elasticsearch:
    rest:
      uris:
        - http://192.168.64.181:9200
        - http://192.168.64.181:9201
        - http://192.168.64.181:9202

logging:
  level:
    tracer: TRACE

二  在 Elasticsearch 中创建 students 索引

在开始运行测试之前,在 Elasticsearch 中先创建 students 索引:

PUT /students
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2,
    "index.max_ngram_diff":30,
    "analysis": {
      "analyzer": {
        "ngram_analyzer": {
          "tokenizer": "ngram_tokenizer"
        }
      },
      "tokenizer": {
        "ngram_tokenizer": {
          "type": "ngram",
          "min_gram": 1,
          "max_gram": 30,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "name": {
        "type": "text",
        "analyzer": "ngram_analyzer"
      },
      "gender": {
        "type": "keyword"
      },
      "birthDate": {
        "type": "date",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第3张图片

 五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第4张图片

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第5张图片

 三 添加Lombok依赖,封装学生数据对象

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第6张图片

  • 封装的数据对象
/**
 * @Document 用于指定索引,也可以用来自动创建索引,
 * 一般索引是自己手动创建*/
@Document(indexName = "students",shards = 3,replicas = 2)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    @Id //使用学生学号作为索引id()
    private Long id;
    private String name;
    private Character gender;
    //设置索引中的字段名,对应实体类中的属性
    //若字段名和属性名相同,可以省略此注解
    @Field("birthDate")
    private String birthDate;
}
  • 新建接口
package cn.tedu.es;

import cn.tedu.es.entity.Student;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**Spring Data Repository 规范
* 只需要定义抽象接口,抽象方法,不需要自己实现
* Repository 底层代码已经实现了所有的增删改成的数据操作代码
* */
public interface StudentRepository
        extends ElasticsearchRepository {//数据类型Student,索引类型Long

}

四 通过 ElasticsearchRepository 实现 CRUD 操作

Spring Data 的 Repository 接口提供了一种声明式的数据操作规范,无序编写任何代码,只需遵循 Spring Data 的方法定义规范即可完成数据的 CRUD 操作。

ElasticsearchRepository 继承自 Repository,其中已经预定义了基本的 CURD 方法,我们可以通过继承 ElasticsearchRepository,添加自定义的数据操作方法。

Repository 方法命名规范

自定义数据操作方法需要遵循 Repository 规范,示例如下:

Elasticsearch(五)Spring Data Elasticsearch - 增删改查API_wanght笔记-CSDN博客

五   创建测试类,添加数据并保存,增删改查

package cn.tedu.es;

import cn.tedu.es.entity.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Optional;

@SpringBootTest
public class Test1 {
    @Autowired
    private StudentRepository r;

    @Test  //import org.junit.jupiter.api.Test;
    public void test1() {
        Student s1 = new Student(9527L, "唐伯虎", '男', "2021-09-29");
        Student s2 = new Student(9528L, "华夫人", '女', "2021-08-29");
        Student s3 = new Student(9529L, "祝枝山", '男', "2021-07-29");
        Student s4 = new Student(9530L, "华安", '男', "2021-06-29");
        Student s5 = new Student(9531L, "旺财", '男', "2021-05-29");
        Student s6 = new Student(9532L, "小强", '男', "2021-04-29");
        Student s7 = new Student(9533L, "秋香", '女', "2021-03-29");
        Student s8 = new Student(9534L, "石榴姐", '男', "2021-02-29");
        r.save(s1);
        r.save(s2);
        r.save(s3);
        r.save(s4);
        r.save(s5);
        r.save(s6);
        r.save(s7);
        r.save(s8);
    }
    //修改
    @Test
    public void test2(){
        Student student = new Student(9533L, "零零", '女', "2021-03-09");
        r.save(student);
    }
    //查询
    @Test
    public void test3(){
        Optional o1 = r.findById(9533L);
        if (o1.isPresent()) { //是否存在/出现
            Student student = o1.get();
            System.out.println(student);
        }
        System.out.println("--------------------");
        Iterable all = r.findAll();
        for (Student s: all){
            System.out.println(s);
        }
    }
    //删除
    @Test
    public void test4(){
        r.deleteById(9533L);
    }
}

六 搜索操作

  • 接口添加搜索的抽象方法
package cn.tedu.es;

import cn.tedu.es.entity.Student;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**Spring Data Repository 规范
* 只需要定义抽象接口,抽象方法,不需要自己实现
* Repository 底层代码已经实现了所有的增删改成的数据操作代码
* */
public interface StudentRepository
        extends ElasticsearchRepository {//数据类型Student,索引类型Long
    // 在 name 中搜索关键词
    List findByName(String nameKey);

    // 在 name 和 birthDate 中搜索
    List findByNameOrBirthDate(String name,String birthDate);

}
  • 测试类编辑搜索方法
   //根据名字搜索
    @Test
    public void test5(){
        List l = r.findByName("华");
        for (Student s:l){
            System.out.println(s);
        }
    }
    //根据名字或者生日搜索
    @Test
    public void test6(){
        List list = r.findByNameOrBirthDate("华", "2021-08-29");
        for(Student s:list){
            System.out.println(s);
        }
    }

六 使用 Criteria 构建查询

Spring Data Elasticsearch 中,可以使用 SearchOperations 工具执行一些更复杂的查询,这些查询操作接收一个 Query 对象封装的查询操作。

Spring Data Elasticsearch 中的 Query 有三种:

  • CriteriaQuery
  • StringQuery
  • NativeSearchQuery
     
  • 自定义搜索方法的类
package cn.tedu.es;

import cn.tedu.es.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class StudentSearcher {
    //执行CriteriaQuery 查询的工具对象
    @Autowired
    private ElasticsearchOperations o;

    // 任意定义的搜索方法
    public List findByName(String nameKey){
        Criteria c = new Criteria("name");
        c.is(nameKey);
        return exec(c);
    }

    public List findByBirthDate(String from,String to){
        Criteria c = new Criteria("birthDate");
        c.between(from,to);
        return exec(c);
    }

    private List exec(Criteria c) {
        // 把条件,封装到一个查询对象
        CriteriaQuery q = new CriteriaQuery(c);
        // 集合SearchHit[SearchHit, SearchHit, SearchHit...]
        SearchHits shs = o.search(q, Student.class);

//        List list =new ArrayList<>();
//        for (SearchHit sh : shs) {
//            Student s = sh.getContent();
//            // 从SearchHit集合中取出的SearchHit放入list集合中
//            list.add(s);
//        }

        // 可以使用集合的 Stream api 和 lambda 语法, 简化上面的代码
        // 映射出SearchHit集合的数据,放到另一个集合中
        List list = shs.stream().map(SearchHit::getContent).collect(Collectors.toList());
        return  list;
    }
}
  • 测试类实现自定义方法
package cn.tedu.es;

import cn.tedu.es.entity.Student;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class Test2 {
    @Autowired
    private StudentSearcher s;

    @Test
    public void test1() {
        List list = s.findByName("华");
        for (Student s : list) {
            System.out.println(s);
        }
    }

    @Test
    public void test2() {
        List list = s.findByBirthDate("2000-01-01", "2030-01-01");
        for (Student s : list) {
            System.out.println(s);
        }
    }
}

七 Spring Data ES 分页操作

根据关键词搜索出来很多结果,会对结果进行分页

  • Pageable -- 封装向服务器提交的分页参数
  • Page -- 封装从服务器返回的搜索结果的一页数据,和分页属性数据
  • Repository api 
List findByName(String nameKey, Pageable pageable)
...

Pageable p =PageRequest.of(0,20);
r.finfByName("华,)
  • 接口创建查询并分页方法

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第7张图片

  • Test1测试类实现这个方法
   //根据名字搜索并分页
    @Test
    public void test5(){
        Pageable p = PageRequest.of(0, 20);//第一页开始,每页20条数据
        Page list = r.findByName("华", p);
        for (Student s:list){
            System.out.println(s);
        }
        System.out.println(list.getNumber());
        System.out.println(list.hasPrevious());
        System.out.println(list.hasNext());
        System.out.println(list.getTotalPages());
        System.out.println(list.getSize());
    }

 八 pd-web项目

  • Open Recent 打开位置:Rabbitmq中
  • 启动他的启动类并配置,然后重启,访问localhost:80  进入拼多商城页面

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第8张图片

 五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第9张图片

 拼多商城搜索条

http://localhost/search/toSearch.html?key=%E6%89%8B%E6%9C%BA

1. pom.xml 添加 es 依赖

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第10张图片

        
			org.springframework.boot
			spring-boot-starter-data-elasticsearch
		
		
			org.projectlombok
			lombok
		

2.application.yml 添加连接地址

spring
....
   elasticsearch:
    rest:
      uris: 
        - http://192.168.64.181:9200
        - http://192.168.64.181:9201
        - http://192.168.64.181:9202

3.添加实体类Item.封装从es 服务器搜索的结果

package com.pd.pojo;

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

@Document(indexName = "pditems") // 指定创建的索引
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Item {
    @Id
    private Long id;
    private String brand;
    private String title;
    @Field("sell_point")//因为这个字段有下划线,需要进行指定
    private String sellPoint;
    private String price;
    private String image;
}

4.创建es包添加 ItemRepository 接口和搜索以及分页的方法: findByTitleOrSellPoint()

package com.pd.es;

import com.pd.pojo.Item;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface ItemRepository
         extends ElasticsearchRepository {//对象类型,数据类型
    //方法名必须要按格式书写
    Page findByTitleOrSellPoint(String key1, String key2, Pageable pageable);
}

5.SearchService接口 以及 实现类

package com.pd.service;

import com.pd.pojo.Item;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface SearchService {
    Page search(String key, Pageable pageable);
}
package com.pd.service.impl;

import com.pd.es.ItemRepository;
import com.pd.pojo.Item;
import com.pd.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private ItemRepository r;

    @Override
    public Page search(String key, Pageable pageable) {
        return r.findByTitleOrSellPoint(key,key,pageable); //pageable分页参数
    }
}

6.SearchController

package com.pd.controller;

import com.pd.pojo.Item;
import com.pd.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class SearchController {
    @Autowired
    private SearchService searchService;
    //.../search/toSearch.html?key=手机&page=1&size=20
    @GetMapping("/search/toSearch.html")
    public String search(Model model, String key, Pageable pageable){
        // Model 是用来向界面传递数据工具
        Page page =
                searchService.search(key, pageable);//搜索结果
        model.addAttribute("page",page);//结果放到model对象中

        return "/search.jsp"; //在这里面显示
    }
}

7.webapp包下Search jsp

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第11张图片

8.重启启动类,在搜索栏搜索"手机",即可搜到关于此产品的信息

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第12张图片

9.search.jsp添加上一页下一页功能

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第13张图片

  • 重启测试:

 五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第14张图片

 10. 搜索框回显搜索的关键词

webapp-->commons-->headers.jsp

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第15张图片

  •  重启测试:

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第16张图片

11 搜索后关键词的高亮显示

  • 商品存储ItemRepository接口中添加高亮显示的注解

注意:

  • SearchHit对象会报错,根据提示的错误找到对象或接口,挨个全部改为SearchHit即可
  • Re'pository api 高亮显示结果 SearchHit , 只能用List 集合存放, 不能用Page,否则会缺少分页属性.

第一步:ItemRepository

package com.pd.es;

import com.pd.pojo.Item;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.HighlightField;
import org.springframework.data.elasticsearch.annotations.HighlightParameters;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

public interface ItemRepository extends ElasticsearchRepository {
    @Highlight(
            parameters = @HighlightParameters(
                    preTags = "",
                    postTags = ""
            ),
            fields = @HighlightField(name = "title")
    )
    List> findByTitleOrSellPoint(String k1, String k2, Pageable pageable);
}

第二步:SearchService接口以及实现类

package com.pd.service;

import com.pd.pojo.Item;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHit;

import java.util.List;

public interface SearchService {
    List> search(String key, Pageable pageable);
}
package com.pd.service.impl;

import com.pd.es.ItemRepository;
import com.pd.pojo.Item;
import com.pd.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private ItemRepository r;

    @Override
    public List> search(String key, Pageable pageable) {
        return r.findByTitleOrSellPoint(key,key,pageable);
    }
}

第三步:SearchController

  • 商品数据的title 设置成高亮结果
  • 所有商品放入List集合
package com.pd.controller;

import com.pd.pojo.Item;
import com.pd.service.SearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

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

@Controller
public class SearchController {

    @Autowired
    private SearchService searchService;

    @GetMapping("/search/toSearch.html")
    public String search(Model model, String key, Pageable pageable){
        List> list = searchService.search(key, pageable);
        Listitems = new ArrayList<>();
        for (SearchHit sh : list) {
            Item it = sh.getContent();
            String title=hlTitle(sh.getHighlightField("title"));
            it.setTitle(title);
            items.add(it);
        }
        model.addAttribute("items",items);
        model.addAttribute("page",pageable);
      // pageable.getPageSize();
      //  pageable.getPageNumber();
        return "/search.jsp";
    }

    private String hlTitle(List title) {
        StringBuilder sb = new StringBuilder();
        for (String s : title) {
            sb.append(s);
        }
        return sb.toString();
    }
}

第四步:search.jsp

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第17张图片

  •  设置高亮效果:

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第18张图片

  •  重启启动类,搜索"电脑",所有结果中电脑这个词显示红色,并且可以使用上一页下一页功能

五阶段--Spring Data Elasticsearch - 增删改查API / 使用 Criteria 构建查询 / Spring Data ES 分页操作 /拼多商城搜索条_第19张图片

你可能感兴趣的:(spring,elasticsearch)