elasticsearch安装:
ik分词安装:
springboot整合:(这篇总结的很到位)
我这里主要将就geo的使用:
如果使用geo功能必须使用ElasticsearchTemplate,必须使用Mapping先去创建然后在添加数据,否则会出现geo类型错误
使用Repository基本查询:
依赖包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Springboot-elasticsearch</groupId>
<artifactId>Springboot-elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 定义公共资源版本 -->
<!--<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath />
</parent> -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<!-- elasticsearch -->
<!-- springboot-data-elasticsearch 提供了面向对象的方式操作elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
VehicleDto实体类
package com.es.dto;
import java.io.Serializable;
import java.util.List;
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;
@Document(indexName = "vehicle", type = "special" , shards = 1, replicas = 0)
public class VehicleDto implements Serializable {
private static final long serialVersionUID = -5483287283894740770L;
@Id
private Long id;
@Field(type = FieldType.Text)
private String carDriver;
@Field(type = FieldType.Text)
private String carType;
//1:ik_smart:做最粗粒度的拆分;2:ik_max_word:做最细粒度的拆分
@Field(type = FieldType.Text,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String carName;
@Field(type = FieldType.Text)
private String status;
@Field(type = FieldType.Text)
private int price;
//嵌套实体使用FieldType.Nested
@Field(type=FieldType.Nested,includeInParent=true)
private List<AddressPointDto> addressPointDto;
public VehicleDto() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCarDriver() {
return carDriver;
}
public void setCarDriver(String carDriver) {
this.carDriver = carDriver;
}
public String getCarType() {
return carType;
}
public void setCarType(String carType) {
this.carType = carType;
}
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public List<AddressPointDto> getAddressPointDto() {
return addressPointDto;
}
public void setAddressPointDto(List<AddressPointDto> addressPointDto) {
this.addressPointDto = addressPointDto;
}
@Override
public String toString() {
return "VehicleDto [id=" + id + ", carDriver=" + carDriver + ", carType=" + carType + ", carName=" + carName
+ ", status=" + status + ", price=" + price + ", addressPointDto=" + addressPointDto + "]";
}
}
嵌套实体AddressPointDto
package com.es.dto;
import java.io.Serializable;
import java.util.Date;
import org.elasticsearch.common.geo.GeoPoint;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import com.fasterxml.jackson.annotation.JsonFormat;
@Document(indexName ="vehiclepoint", type = "specialpoint" , shards = 1, replicas = 0)
public class AddressPointDto implements Serializable {
private static final long serialVersionUID = -5483287283894740770L;
@Id
private Long id;
// @Field(type = FieldType.String)//1.5.8 spring-boot使用类型
//1:ik_smart:做最粗粒度的拆分;2:ik_max_word:做最细粒度的拆分
@Field(type = FieldType.Text,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")//使用ik分词器
private String name;
//必须使用@Field注解,否则使用精确匹配查询字段需要type.Keyword
// @Field(type = FieldType.Keyword)
@Field(type = FieldType.Text)
// @Field(type = FieldType.String)//1.5.8 spring-boot使用类型
private String type;
@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 xjTime;
// @Field(type = FieldType.String,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")//1.5.8 spring-boot使用类型
@Field(type = FieldType.Text,analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String remark;
@GeoPointField
private GeoPoint address;
public AddressPointDto() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public GeoPoint getAddress() {
return address;
}
public void setAddress(GeoPoint address) {
this.address = address;
}
public Date getXjTime() {
return xjTime;
}
public void setXjTime(Date xjTime) {
this.xjTime = xjTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
@Override
public String toString() {
return "VehiclePointEsDto [id=" + id + ", name=" + name + ", type=" + type + ", xjTime=" + xjTime + ", remark="
+ remark + ", address=" + address + "]";
}
}
VehicleRepository接口
package com.es.service;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Component;
import com.es.dto.VehicleDto;
@Component
public interface VehicleRepository extends ElasticsearchRepository<VehicleDto, Long>{
/**
* @return
*/
List<VehicleDto> findByCarDriver(String carDriver,Pageable pageable);
/**
* @param name
* @return
*/
List<VehicleDto> findByAddressPointDtoName(String name,Pageable pageable);
/**
* @param id1
* @param id2
* @return
*/
List<VehicleDto> findByCarDriverAndPrice(String carDriver,int price,Pageable pageable);
/**
* @return
*/
List<VehicleDto> findByCarDriverOrCarType(String carDriver,String carType,Pageable pageable);
/**
* @param id1
* @param id2
* @return
*/
List<VehicleDto> findByPriceBetween(int price1, int price2);
}
VehicleService接口
package com.es.api;
import java.util.List;
import org.springframework.data.domain.Pageable;
import com.es.dto.VehicleDto;
public interface VehicleService {
public void set(VehicleDto dto);
public void setAll(Iterable<VehicleDto> ite);
public void del(Long id);
public VehicleDto findById(Long id);
public List<VehicleDto> findAll();
public List<VehicleDto> findCarDriver(String carDriver,Pageable pageable);
public List<VehicleDto> findByAddressPointDtoName(String name,Pageable pageable);
public List<VehicleDto> findByCarDriverAndPrice(String carDriver,int price,Pageable pageable);
public List<VehicleDto> findByCarDriverOrCarType(String carDriver,String carType,Pageable pageable);
public List<VehicleDto> findByPriceBetween(int price1, int price2);
}
VehicleServiceImpl实现类
package com.es.service.impl;
import java.util.List;
import java.util.Optional;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.es.api.VehicleService;
import com.es.dto.VehicleDto;
import com.es.service.VehicleRepository;
@Service
public class VehicleServiceImpl implements VehicleService{
private @Autowired VehicleRepository vehicleRepository;
@Override
public void set(VehicleDto dto) {
vehicleRepository.save(dto);
}
@Override
public void setAll(Iterable<VehicleDto> ite) {
// vehicleRepository.save(ite);
vehicleRepository.saveAll(ite);
}
@Override
public void del(Long id) {
vehicleRepository.deleteById(id);
}
@Override
public VehicleDto findById(Long id) {
// VehicleEsDto dto = vehicleRepository.findOne(id);
// return dto;
Optional<VehicleDto> dto = vehicleRepository.findById(id);
return dto.get();
}
@Override
public List<VehicleDto> findAll() {
List<VehicleDto> list = Lists.newArrayList(vehicleRepository.findAll());
return list;
}
@Override
public List<VehicleDto> findCarDriver(String carDriver, Pageable pageable) {
List<VehicleDto> list = vehicleRepository.findByCarDriver(carDriver, pageable);
return list;
}
@Override
public List<VehicleDto> findByCarDriverAndPrice(String carDriver, int price, Pageable pageable) {
List<VehicleDto> list = vehicleRepository.findByCarDriverAndPrice(carDriver, price, pageable);
return list;
}
@Override
public List<VehicleDto> findByCarDriverOrCarType(String carDriver, String carType, Pageable pageable) {
List<VehicleDto> list = vehicleRepository.findByCarDriverOrCarType(carDriver, carType, pageable);
return list;
}
@Override
public List<VehicleDto> findByPriceBetween(int price1, int price2) {
List<VehicleDto> list = vehicleRepository.findByPriceBetween(price1, price2);
return list;
}
@Override
public List<VehicleDto> findByAddressPointDtoName(String name,Pageable pageable) {
List<VehicleDto> list = vehicleRepository.findByAddressPointDtoName(name,pageable);
return list;
}
}
ElasticsearchTemplate 使用
VehicleTemplateService接口
package com.es.api;
import java.util.List;
import com.es.dto.VehicleDto;
public interface VehicleTemplateService {
public void bulkIndex(List<VehicleDto> personList);
public List<VehicleDto> queryForList(double lat, double lon);
public List<VehicleDto> queryDto();
}
VehicleTemplateServiceImpl实现类
package com.es.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;
import com.es.api.VehicleTemplateService;
import com.es.dto.VehicleDto;
@Service
public class VehicleTemplateServiceImpl implements VehicleTemplateService{
private @Autowired ElasticsearchTemplate elasticsearchTemplate;
public void bulkIndex(List<VehicleDto> vehicleDto) {
int counter = 0;
List<IndexQuery> queries = new ArrayList<>();
//https://github.com/spring-projects/spring-data-elasticsearch/wiki/Geo-indexing-and-request
//必须使用Mapping先去创建然后在添加数据,否则会出现geo类型错误
elasticsearchTemplate.createIndex(VehicleDto.class);
elasticsearchTemplate.putMapping(VehicleDto.class);
for (VehicleDto vehiclePointEsDto : vehicleDto) {
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(vehiclePointEsDto.getId() + "");
indexQuery.setObject(vehiclePointEsDto);
//上面的那几步也可以使用IndexQueryBuilder来构建
//IndexQuery index = new IndexQueryBuilder().withId(VehiclePointEsDto.getId() + "").withObject(VehicleDto).build();
queries.add(indexQuery);
if (counter % 500 == 0) {
elasticsearchTemplate.bulkIndex(queries);
queries.clear();
System.out.println("bulkIndex counter : " + counter);
}
counter++;
}
if (queries.size() > 0) {
elasticsearchTemplate.bulkIndex(queries);
System.out.println("运行完成");
}
System.out.println("bulkIndex completed.");
}
/**
*
geo_distance: 查找距离某个中心点距离在一定范围内的位置
geo_bounding_box: 查找某个长方形区域内的位置
geo_distance_range: 查找距离某个中心的距离在min和max之间的位置
geo_polygon: 查找位于多边形内的地点。
sort可以用来排序
*/
@Override
public List<VehicleDto> queryForList(double lat, double lon) {
Long nowTime = System.currentTimeMillis();
//查询某经纬度10000米范围内
GeoDistanceQueryBuilder builder = QueryBuilders.geoDistanceQuery("addressPointDto.address").point(lat, lon)
.distance(10000, DistanceUnit.METERS);
GeoDistanceSortBuilder sortBuilder = SortBuilders
// .geoDistanceSort("address")
.geoDistanceSort("addressPointDto.address",new GeoPoint(lat, lon))//高版本使用
.point(lat, lon)
.unit(DistanceUnit.METERS)
.order(SortOrder.ASC);
//分页查询50条
// Pageable pageable = new PageRequest(0, 50);
//查询经纬度10000米范围内,并根据坐标排序
// NativeSearchQueryBuilder builder1 = new NativeSearchQueryBuilder().withFilter(builder).withPageable(pageable).withSort(sortBuilder);
/**
* 使用QueryBuilder
* termQuery("key", obj) 完全匹配(不进行分词匹配)
* termsQuery("key", obj1, obj2..) 一次匹配多个值
* matchQuery("key", Obj) 单个匹配(分词匹配), field不支持通配符, 前缀具高级特性
* multiMatchQuery("text", "field1", "field2"..); 匹配多个字段, field有通配符忒行
* matchAllQuery(); 匹配所有文件
* matchPhraseQuery() 类似于数据库里的“%名字57%”这种
*/
//查询经纬度10000米范围内,name字段的值为名字57,并根据坐标排序
// QueryBuilder queryBuilder = QueryBuilders.termQuery("name", "名字57");
// NativeSearchQueryBuilder builder1 = new NativeSearchQueryBuilder().withQuery(queryBuilder).withFilter(builder).withPageable(pageable).withSort(sortBuilder);
// NativeSearchQueryBuilder builder1 = new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("name", "名字57")).withFilter(builder).withPageable(pageable).withSort(sortBuilder);
/**
* 组合查询
* must(QueryBuilders) : AND
* mustNot(QueryBuilders): NOT
* should: : OR
*/
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("carDriver", "李四")).should(QueryBuilders.matchQuery("addressPointDto.name", "李四"));
// QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("remark", "祖国"));
// QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name", "名字57")).mustNot(QueryBuilders.matchQuery("id", "43")).should(QueryBuilders.matchQuery("type", "类型36"));
NativeSearchQueryBuilder builder1 = new NativeSearchQueryBuilder().withQuery(queryBuilder).withFilter(builder).withPageable(PageRequest.of(0,50)).withSort(sortBuilder);
SearchQuery searchQuery = builder1.build();
//queryForList默认是分页,走的是queryForPage,默认10个
List<VehicleDto> VehiclePointEsDtoList = elasticsearchTemplate.queryForList(searchQuery, VehicleDto.class);
System.out.println("耗时:" + (System.currentTimeMillis() - nowTime));
return VehiclePointEsDtoList;
}
@Override
public List<VehicleDto> queryDto() {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("carDriver", "张三1"));
SearchQuery searchQuery = builder.build();
//queryForList默认是分页,走的是queryForPage,默认10个
List<VehicleDto> VehiclePointEsDtoList = elasticsearchTemplate.queryForList(searchQuery, VehicleDto.class);
return VehiclePointEsDtoList;
}
}
elasticsearchTest 测试类
package com.es;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.junit4.SpringRunner;
import com.es.api.VehicleService;
import com.es.api.VehicleTemplateService;
import com.es.dto.AddressPointDto;
import com.es.dto.VehicleDto;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ElasticSearchApplication.class)
public class elasticsearchTest {
@Autowired
private VehicleService vehicleService;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private VehicleTemplateService vehicleTemplateService;
@Test
public void queryGeos(){
double lat = 39.929986;
double lon = 116.395645;
List<VehicleDto> list = vehicleTemplateService.queryForList(lat, lon);
System.out.println(list);
}
@Test
public void bulkIndex(){
List<VehicleDto> list = new ArrayList<>();
double lat = 39.929986;
double lon = 116.395645;
List<AddressPointDto> addressPointDto = new ArrayList<>();
for (int i = 1 ; i < 10; i++) {
double max = 0.00001;
double min = 0.000001;
Random random = new Random();
double s = random.nextDouble() % (max - min + 1) + max;
DecimalFormat df = new DecimalFormat("######0.000000");
// System.out.println(s);
String lons = df.format(s + lon);
String lats = df.format(s + lat);
Double dlon = Double.valueOf(lons);
Double dlat = Double.valueOf(lats);
AddressPointDto person = new AddressPointDto();
person.setId(Long.valueOf(i));
person.setName("李四" + i);
person.setType("类型" + i);
person.setXjTime(new Date());
if(i%2 == 0) {
person.setRemark("我爱中国,我爱祖国"+i);
}
if(i%3 == 0) {
person.setRemark("我不爱美国,我爱祖国"+i);
}else{
person.setRemark("我不爱日本,我爱祖国"+i);
}
person.setAddress(new GeoPoint(dlat,dlon));
addressPointDto.add(person);
}
for (int j = 0; j < 10; j++) {
VehicleDto vehicleDto = new VehicleDto();
vehicleDto.setId(Long.valueOf(j));
vehicleDto.setCarDriver("李四"+j);
vehicleDto.setCarName(j+".2米");
vehicleDto.setCarType(j+"");
vehicleDto.setPrice(j*1000);
vehicleDto.setStatus("1");
vehicleDto.setAddressPointDto(addressPointDto);
list.add(vehicleDto);
}
System.out.println("list:"+list);
vehicleTemplateService.bulkIndex(list);
}
@Test
public void queryDto(){
// Pageable pageable = new PageRequest(0, 5);
// NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("carDriver", "张三1"));
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("addressPointDto.name", "张三1")).withPageable(PageRequest.of(0,5));
SearchQuery searchQuery = builder.build();
//queryForList默认是分页,走的是queryForPage,默认10个
List<VehicleDto> vehicleDto = elasticsearchTemplate.queryForList(searchQuery, VehicleDto.class);
System.err.println("findAll:"+vehicleDto);
}
@Test
public void findByAddressPointDtoName(){
String name = "张三1";
List<VehicleDto> list = vehicleService.findByAddressPointDtoName(name,PageRequest.of(0,5));
System.err.println("findAll:"+list);
}
@Test
public void findByCarDriverAndPrice(){
String carDriver = "张三1";
int price = 1000;
// Pageable pageable = new PageRequest(0, 5);
List<VehicleDto> list = vehicleService.findByCarDriverAndPrice(carDriver, price, PageRequest.of(0,5));
System.err.println("findAll:"+list);
}
@Test
public void findAll(){
List<VehicleDto> list = vehicleService.findAll();
System.err.println("findAll:"+list);
}
@Test
public void del(){
Long id = 18L;
vehicleService.del(id);
}
/**
* 创建Index
*/
@Test
public void createIndex(){
List<VehicleDto> list = new ArrayList<>();
double lat = 39.929986;
double lon = 116.395645;
List<AddressPointDto> addressPointDto = new ArrayList<>();
for (int i = 1 ; i < 10; i++) {
double max = 0.00001;
double min = 0.000001;
Random random = new Random();
double s = random.nextDouble() % (max - min + 1) + max;
DecimalFormat df = new DecimalFormat("######0.000000");
// System.out.println(s);
String lons = df.format(s + lon);
String lats = df.format(s + lat);
Double dlon = Double.valueOf(lons);
Double dlat = Double.valueOf(lats);
AddressPointDto person = new AddressPointDto();
person.setId(Long.valueOf(i));
person.setName("张三" + i);
person.setType("类型" + i);
person.setXjTime(new Date());
if(i%2 == 0) {
person.setRemark("我爱中国,我爱祖国"+i);
}
if(i%3 == 0) {
person.setRemark("我不爱美国,我爱祖国"+i);
}else{
person.setRemark("我不爱日本,我爱祖国"+i);
}
person.setAddress(new GeoPoint(dlat,dlon));
addressPointDto.add(person);
}
for (int j = 30; j < 40; j++) {
VehicleDto vehicleDto = new VehicleDto();
vehicleDto.setId(Long.valueOf(j));
vehicleDto.setCarDriver("赵六"+j);
vehicleDto.setCarName(j+".2米");
vehicleDto.setCarType(j+"");
vehicleDto.setPrice(j*1000);
vehicleDto.setStatus("1");
vehicleDto.setAddressPointDto(addressPointDto);
list.add(vehicleDto);
}
// vehicleService.set(vehicleDto);
System.out.println("list:"+list);
//如果需要使用到geo必须用ElasticsearchTemplate的方式添加
vehicleService.setAll(list);
}
}
github地址:https://github.com/LX1309244704/SpringBoot-master/tree/master/springboot-es