网上一堆复杂的操作,其实spring-data-elsaticsearch可以很简便的写,它遵循springdata的写法。
elasticsearch选用的是7.16版本,兼容7.x版本,主要使用的是spring-data-elasticsearch 因为感觉这个很好用 其他的工具也可以,主要是顺心顺手( •̀ ω •́ )
添加pom.xml依赖
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.17.6</elasticsearch.version>
</properties>
<dependencies>
<!--elasticsearch data-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--我study主要写在测试类里面 所以导入测试类依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.5</version>
<scope>test</scope>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
编写yml文件
server:
port: 8080
spring:
elasticsearch:
uris: localhost:9200
编写实体类
package com.example.elasticsearchstudy.domain;
import lombok.Data;
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;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @author liwenzhu
*/
@Component
@Data
@Document(indexName = "hotel")
public class Hotel implements Serializable {
/** 酒店id*/
@Id
private String id;
/** 酒店名称*/
@Field(type = FieldType.Keyword)
private String name;
/** 酒店地址 */
@Field(type = FieldType.Keyword)
private String address;
/** 酒店价格 */
@Field(type = FieldType.Double)
private Integer price;
/** 酒店评分 */
@Field(type = FieldType.Double)
private Double score;
/** 酒店品牌 */
@Field(type = FieldType.Keyword)
private String brand;
/** 所在城市 */
@Field(type = FieldType.Keyword)
private String city;
/** 酒店星级 酒店星级,1星到5星,1钻到5钻 */
@Field(type = FieldType.Keyword)
private String starName;
/** 商圈 */
@Field(type = FieldType.Text,analyzer = "ik_max_word")
private String business;
/** 纬度 */
@Field(type = FieldType.Keyword)
private String latitude;
/** 经度 */
@Field(type = FieldType.Keyword)
private String longitude;
/** 酒店图片 */
@Field(type = FieldType.Keyword)
private String pic;
}
新建一个repository/HotelRepository
package com.example.elasticsearchstudy.repository;
import com.example.elasticsearchstudy.domain.Hotel;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Service;
/**
* @author liwenzhu
*/
@Service
public interface HotelRepository extends ElasticsearchRepository<Hotel,String> {
}
编写测试类
package com.example.elasticsearchstudy;
import com.example.elasticsearchstudy.domain.Hotel;
import com.example.elasticsearchstudy.repository.HotelRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@RunWith(SpringRunner.class)
@SpringBootTest
public class LiwenzhuTest {
@Resource
private HotelRepository repository;
@Test
public void testCreateDoc() {
Hotel hotel = new Hotel();
hotel.setName("京西大酒店");
hotel.setAddress("xxx路");
hotel.setPrice(2000);
hotel.setScore(4.0);
hotel.setBrand("李文铸牌");
hotel.setCity("福州");
hotel.setStarName("四星");
hotel.setBusiness("福州儿童公园路");
hotel.setLatitude("30.251433");
hotel.setLongitude("120.47522");
hotel.setPic("https://m.tuniucdn.com/filebroker/cdn/res/07/36/073662e1718fccefb7130a9da44ddf5c_w200_h200_c1_t0.jpg");
repository.save(hotel);
}
}
因为是spring-data-elasticsearch 所以crud是遵循spring-data的风格的
增加和修改都是save方法
删除就是delete方法,不过他删除都是根据id删的,所以要么deleteById,要么就是delete实体类的id有值
查询遵循spring-data风格
比如你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。
高亮显示
在repository方法上使用@Highlight注解即可
然后在SearchHit就可以看到获取的高亮信息了,比原生的方法好用很多。
@Highlight(fields = {
@HighlightField(name = "city"),
@HighlightField(name = "name")
})
List<SearchHit<Hotel>> findByCityAndName(String city,String name);
模糊查询
遵循JPA的查询规范即可 findByxxxContains 相当于 % xxx %,而findByxxxLike 相当于 xxx %,所以模糊匹配根据需求来。
List<Hotel> findByNameContains(String name);
分页
分页的写法也非常简单,参数多加一个Pageable就可以了
同样是在repository层
List<Hotel> findByNameContains(String name,Pageable pageable);
调用层
//这个地方正常page和size是参数传进来的,但是因为是Test类,不允许这样的操作,所以在这里备注一下。
@Test
public void likeQuery() {
//分页参数
int page = 1;
int size = 10;
List<Hotel> nameList = hotelRepository.findByNameContains("北京",PageRequest.of(page - 1, size));
System.out.println(nameList);
}
全文检索
实体类加上对应的字段 这个额外字段必须和索引库的一致
/** * 由其他属性copy而来,主要用于搜索功能,不需要储存数据 */
@JsonIgnore @Field(type = FieldType.Text, analyzer = "ik_max_word", ignoreFields = "descriptiveContent", excludeFromSource = true)
private String descriptiveContent;
repository层
/**
* 全文检索
* @param descriptiveContent 检索的字段
* @return
*/
List<Hotel> findByAll(String descriptiveContent);
排序
/**
* 排序
* @param descriptiveContent 检索的字段
* @return
*/
List<Hotel> findByAllOrderByPriceDesc(String descriptiveContent);
gitee: https://gitee.com/soulsinger/elasticsearch-study.git