前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >spring-data-elasticsearch

spring-data-elasticsearch

作者头像
爱撒谎的男孩
发布2019-12-31 15:42:32
3.1K0
发布2019-12-31 15:42:32
举报
文章被收录于专栏:码猿技术专栏

文章目录

1. spring-data-elasticsearch

1.1. @Document

1.2. @Field

1.3. @Id

1.4. Date类型的存储

1.5. 创建一个实体类

1.6. 定义查询接口

1.6.1. 常用方法如下:

1.6.2. 自定义查询

1.6.2.1. 实例

1.7. 使用@Query定义自己的es语句

1.8. 控制结果集数量

1.9. 分页查询

1.9.1. 单条件分页排序

1.9.2. 多条件分页排序

1.10. 日期格式问题

1.11. 使用ElasticsearchTemplate

1.12. 参考文档

spring-data-elasticsearch

@Document

  • @Document(indexName = "es",type = "user",shards = 5,replicas = 0) : 标注在实体类上,声明存储的索引和类型
    • indexName: 索引名称
    • type:索引类型
    • shards:分片的数量
    • replicas:副本的数量
    • refreshInterval: 刷新间隔
    • indexStoreType:索引文件存储类型

@Field

  • 标注在属性上,用来指定属性的类型。其中的属性如下:
    • analyzer:指定分词器,es中默认使用的标准分词器,比如我们需要指定中文IK分词器,可以指定值为ik_max_word
    • type: 指定该属性在es中的类型,其中的值是FileType类型的值,比如FileType.Text类型对应es中的text类型
    • index:指定该词是否需要索引,默认为true
    • store:指定该属性内容是否需要存储,默认为
    • fielddata :指定该属性能否进行排序,因为es中的text类型是不能进行排序(已经分词了)
    • searchAnalyzer : 指定搜索使用的分词器
  • 在插入数据之前我们需要先运行程序添加mapping,对于没有指定@Field的属性此时是不会创建索引的,而是在插入数据的时候自动创建索引。但是对于@Field注解标注的属性如果没有先加载生成mapping,等到插入数据的时候是没有效果的
  • 如果使用该注解,那么必须指定其中的type属性

@Id

  • 主键注解,标识一个属性为主键

Date类型的存储

  • es中默认存储Date类型的是一个时间戳,如果我们需要指定格式的存储,那么需要在@Field这个注解中指定日期的格式。如下:
代码语言:javascript
复制
@Field(type = FieldType.Date,format = DateFormat.custom, pattern ="yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
 private Date birthday;

创建一个实体类

代码语言:javascript
复制

/**
 * @Document : 这个是ES的注解,在类使用,指定实体类的索引和类型。默认所有的属性都是索引的
 *             1、indexName : 指定索引
 *             2、type:指定类型
 *             3、shards:指定分片的数量
 *             4、replicas:指定副本的数量
 */
@Document(indexName = "es",type = "user",shards = 5,replicas = 0)
public class User {
    @Id   //指定这个是主键
    private Integer userId;

    @Field(type = FieldType.Text,analyzer = "ik_max_word",fielddata = true,store = false)
    private String userName;

    private String password;

    @Field(type = FieldType.Date, store = true, format = DateFormat.custom, pattern ="yyyy-MM-dd HH:mm:ss")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern ="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date birthday;

    private List<String> hobbies;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                ", hobbies=" + hobbies +
                '}';
    }
}

定义查询接口

  • 官网上提供了各种各样的方法,我们使用继承ElasticsearchRepository这个接口的方式拓展查询接口,基本的接口:
代码语言:javascript
复制
    public interface UserRepo extends ElasticsearchRepository<User,Integer> {
    //不需要实现其中的方法,只需要继承即可,spring-data-es会为我们自动完成
}

常用方法如下:

  1. index(T t) :添加数据
  2. save(T t):添加数据
  3. count(): 获取数据总数
  4. findAll():获取所有的数据,返回的是一个java.lang.Iterable
  5. Iterable<T> findAllById(Iterable<ID> ids):根据Id批量返回数据
  6. saveAll(Iterable entity) :批量保存数据,可以传入List
  7. delete(T t) : 删除指定的实体类,只需要指定实体类中的Id即可
  8. deleteAll():删除所有的数据
  9. deleteById(ID Id):根据Id删除数据
  10. existsById(ID Id): 判断指定Id的数据是否存在
代码语言:javascript
复制
    //添加数据
    @Test
    public void test3(){
        User user=new User();
        user.setUserId(1);
        user.setUserName("郑元梅");
        user.setBirthday(new Date());
        user.setPassword("12345678");
        List<String> hobbies=new ArrayList<>();
        hobbies.add("篮球");
        hobbies.add("足球");
        user.setHobbies(hobbies);
//        userRepo.save(user);   //调用其中的save方法保存信息
        userRepo.index(user);  //调用index方法添加数据
    }



    //获取其中的所有数据
    @Test
    public void test4(){
        Iterable<User> iterable=userRepo.findAll();
        Iterator<User> iterator=iterable.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }


    @Test
    public  void test5(){
        List<User> users=new ArrayList<>();
        User user=new User();
        user.setUserId(4);
        user.setUserName("张三");
        user.setBirthday(new Date());
        user.setPassword("12345678");
        List<String> hobbies=new ArrayList<>();
        hobbies.add("台球");
        hobbies.add("足球");
        user.setHobbies(hobbies);

        User user1=new User();
        user1.setUserId(5);
        user1.setUserName("郑元梅");
        user1.setBirthday(new Date());
        user1.setPassword("12345678");
        user1.setHobbies(hobbies);

        users.add(user);
        users.add(user1);
        userRepo.saveAll(users);  //保存List中的所有数据
    }

    //删除指定的数据
    @Test
    public void test6(){
        User user=new User();
        user.setUserId(5);
        userRepo.delete(user);
    }


    @Test
    public void test7(){
        List<User> users=userRepo.selectAll();
        for (User user
             :users
             ) {
            System.out.println(user);
        }
    }

自定义查询

  • spring-data-elasticsearch为我们自动完成了许多的查询,我们只需要按照其中的规范使用即可。
    • 查询方法定义以get或者find开头即可
  • 关于es中各种查询,我们可以参照下表进行定义,文档

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

Between

findByPriceBetween

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

LessThanEqual

findByPriceLessThan

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

GreaterThanEqual(>=)

findByPriceGreaterThan

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Before(<=)

findByPriceBefore

{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}

After

findByPriceAfter

{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}

Like(?%)(如果需要实现%?%可以使用fuzzy)

findByNameLike

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

StartingWith

findByNameStartingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}

EndingWith

findByNameEndingWith

{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}

Contains/Containing

findByNameContaining

{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}

In

findByNameIn(Collection<String>names)

{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}

NotIn

findByNameNotIn(Collection<String>names)

{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}

Near

findByStoreNear

Not Supported Yet !

True

findByAvailableTrue

{"bool" : {"must" : {"field" : {"available" : true}}}}

False

findByAvailableFalse

{"bool" : {"must" : {"field" : {"available" : false}}}}

OrderBy

findByAvailableTrueOrderByNameDesc

{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

实例
代码语言:javascript
复制
package com.techwells.es;
import com.techwells.beans.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import java.util.Date;
import java.util.List;
public interface UserRepo extends ElasticsearchRepository<User,Integer>{

    /**
     * 根据userId获取用户信息
     * @param userId
     * @return
     */
    User findUserByUserId(Integer userId);

    /**
     * 根据用户查找用户信息
     * @param userName
     * @return
     */
    List<User> findByUserName(String userName);



    /**
     * 根据用户名和密码查找用户信息,使用的是must查询
     * 参数的顺序不能颠倒
     * @param userName
     * @param password
     * @return
     */
    List<User> findByUserNameAndPassword(String userName,String password);


    /**
     * 根据用户名或者地址进行查询,满足其一即可,使用的是should
     * 参数不能颠倒
     * @param userName
     * @param address
     * @return
     */
    List<User> findByUserNameOrAddress(String userName,String address);


    /**
     * 使用@Query注解自定义查询语句,其中的?是占位符,0表示第一个参数
     * @param userName
     * @return
     */
    @Query("{\n" +
            "    \"bool\": {\n" +
            "      \"must\": [\n" +
            "        {\n" +
            "          \"match\": {\n" +
            "            \"userName\": \"?0\"\n" +
            "          }\n" +
            "        }\n" +
            "      ]\n" +
            "    }\n" +
            "  }")
    List<User> selectByUserName(String userName);


    /**
     * 查询密码不为null的用户信息
     * @return
     */
    @Query("{\n" +
            "    \"bool\": {\n" +
            "      \"must\":{\n" +
            "        \"exists\":{\n" +
            "          \"field\":\"password\"\n" +
            "        }\n" +
            "      }\n" +
            "    }\n" +
            "  }")
    List<User> findByPasswordIsNotNull();


    /**
     * 查询密码为null的用户信息
     * @return
     */
    @Query("{\n" +
            "    \"bool\": {\n" +
            "      \"must_not\":{\n" +
            "        \"exists\":{\n" +
            "          \"field\":\"password\"\n" +
            "        }\n" +
            "      }\n" +
            "    }\n" +
            "  }")
    List<User> findByPasswordIsNull();


    /**
     * 查询密码不是password的用户信息,使用的must_not
     * @param password
     * @return
     */
    List<User> findByPasswordNot(String password);

    /**
     * 查询用户名是userName但是密码表示password的信息,必须同时满足
     * @param userName
     * @param password
     * @return
     */
    List<User> findByUserNameAndPasswordNot(String userName,String password);


    /**
     * 查询年龄在from-to之间的用户,包含form和to,使用的是range查询
     * @param from  起始
     * @param to    截止
     * @return
     */
    List<User> findByAgeBetween(Integer from,Integer to);


    /**
     * 查询年龄小于age的用户信息
     * @param age  年龄
     * @return
     */
    List<User> findByAgeLessThan(Integer age);


    /**
     * 年龄小于等于age的用户信息
     */
    List<User> findByAgeLessThanEqual(Integer age);

    /**
     * 年龄大于age的用户
     * @param age
     * @return
     */
    List<User> findByAgeGreaterThan(Integer age);

    /**
     * 年龄大于等于age的用户
     * @param age
     * @return
     */
    List<User> findByAgeGreaterThanEqual(Integer age);

    /**
     * 年龄小于等于age的用户信息
     * @param age
     * @return
     */
    List<User> findByAgeBefore(Integer age);


    /**
     * 年龄大于等于age的用户
     * @param age
     * @return
     */
    List<User> findByAgeAfter(Integer age);


    /**
     * 模糊查找,密码中以pwd开头用户信息,`content%`,
     * @param content
     * @return
     */
    List<User> findByPasswordLike(String content);

    /**
     * 查询密码中包含content的用户信息  %content%
     * @param content
     * @return
     */
    List<User> findByPasswordContaining(String content);

    /**
     * 查询密码以pwd开头的用户信息,和Like一样的效果
     * @param pwd
     * @return
     */
    List<User> findByPasswordStartingWith(String pwd);


    /**
     * 查询密码以pwd结尾的用户信息
     * @param pwd
     * @return
     */
    List<User> findByPasswordEndingWith(String pwd);

    /**
     * 查找年龄在集合中的用户信息
     * @param ages
     * @return
     */
    List<User> findByAgeIn(List<Integer> ages);

    /**
     * 查找年龄不在集合中的用户信息
     * @param ages
     * @return
     */
    List<User> findByAgeNotIn(List<Integer> ages);


    /**
     * 根据用户名查询并且按照年龄降序排列
     * @param userName
     * @return
     */
    List<User> findByUserNameOrderByAgeDesc(String userName);

    /**
     * 根据用户名查询并且按照年龄降序排列、用户名升序排列
     * @param userName
     * @return
     */
    List<User> findByUserNameOrderByAgeDescUserNameAsc(String userName);


    /**
     * 根据出生日期进行降序排列
     * @param userName
     * @return
     */
    List<User> findByUserNameOrderByBirthdayDesc(String userName);

    /**
     * 返回前2条数据
     * @param userName
     * @return
     */
    List<User> findTop2ByUserName(String userName);
    
    /**
     * 根据用户名分页查询
     * @param userName
     * @param pageable
     * @return
     */
    Page<User> findByUserName(String userName, Pageable pageable);
}

使用@Query定义自己的es语句

代码语言:javascript
复制
/**
     * 使用@Query注解自定义查询语句,其中的?是占位符,0表示第一个参数
     * @param userName
     * @return
     */
    @Query("{\n" +
            "    \"bool\": {\n" +
            "      \"must\": [\n" +
            "        {\n" +
            "          \"match\": {\n" +
            "            \"userName\": \"?0\"\n" +
            "          }\n" +
            "        }\n" +
            "      ]\n" +
            "    }\n" +
            "  }")
    List<User> selectByUserName(String userName);

控制结果集数量

代码语言:javascript
复制
/**
     * 返回前2条数据
     * @param userName
     * @return
     */
    List<User> findTop2ByUserName(String userName);

分页查询

  • https://www.tianmaying.com/tutorial/spring-jpa-page-sort
  • 直接使用org.springframework.data.domain.Pageable进行分页排序即可
    • page:从0开始,第几页,默认为0
    • size:每页显示的数量
    • sort:排序的方向
  • 其中的方法如下:
    • getTotalElements():返回数据的总数,不是分页的总数,而是根据条件查询到的全部的数据的总数
    • getContent():获取分页的数据集合List<T>
    • getTotalPages():获取总共几页的数据
    • iterator():获取迭代器
    • 剩余的方法如下:
代码语言:javascript
复制
public interface Slice<T> extends Streamable<T> {

	//返回当前是第几页
	int getNumber();

	//返回每页显示的数量
	int getSize();

	//返回当前页获取到的元素数量
	int getNumberOfElements();

	//返回当前页元素的集合
	List<T> getContent();

	//判断当前页是否存在数据
	boolean hasContent();

	//获取排序的Sort
	Sort getSort();

	//判断当前页是否是第一页
	boolean isFirst();

	//判断当前页是否是最后一页
	boolean isLast();

	//判断是否还有下一页
	boolean hasNext();

	//判断是否有前一页
	boolean hasPrevious();

	//返回当前页的pageable
	default Pageable getPageable() {
		return PageRequest.of(getNumber(), getSize(), getSort());
	}

	//返回下一页的Pageable
	Pageable nextPageable();

	//返回前一页的pageable
	Pageable previousPageable();

    
	<U> Slice<U> map(Function<? super T, ? extends U> converter);
}

单条件分页排序

  • 只使用了一个字段进行排序
代码语言:javascript
复制
@Test
   public void test3(){
       Sort sort=new Sort(Sort.Direction.DESC,"age");
       Pageable pageable=new PageRequest(9,1,sort);
       Page<User> users=userRepo.findByUserName("李",pageable);
       System.out.println(users.getTotalPages());
       for (User user:users.getContent()) {
           System.out.println(user);
       }
   }

多条件分页排序

  • 使用Order进行排序条件
代码语言:javascript
复制
@Test
  public void test3(){
      List<Sort.Order> orders=new ArrayList<>();
      orders.add(new Sort.Order(Sort.Direction.DESC,"age"));//按照年龄降序排列
      orders.add(new Sort.Order(Sort.Direction.ASC,"userId"));  //按照用户Id升序排列
      Sort sort=new Sort(orders);  //使用orders

      Pageable pageable=new PageRequest(0,10,sort);
      Page<User> users=userRepo.findByUserName("李",pageable);
      System.out.println(users.getTotalPages());
      for (User user:users.getContent()) {
          System.out.println(user);
      }
  }

日期格式问题

  • 未完

使用ElasticsearchTemplate

  • 未完 ………..待续…………………

参考文档

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • spring-data-elasticsearch
    • @Document
      • @Field
        • @Id
          • Date类型的存储
            • 创建一个实体类
              • 定义查询接口
                • 常用方法如下:
                • 自定义查询
              • 使用@Query定义自己的es语句
                • 控制结果集数量
                  • 分页查询
                    • 单条件分页排序
                    • 多条件分页排序
                  • 日期格式问题
                    • 使用ElasticsearchTemplate
                      • 参考文档
                      相关产品与服务
                      Elasticsearch Service
                      腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档