探讨
分词问题
保存的数据text会被分词,term搜索内容不分词,match搜索内容分词:https://blog.csdn.net/egg1996911/article/details/82380026
https://www.cnblogs.com/austinspark-jessylu/p/6878370.html
所以可以用逗号作为分词的依据
if (CollectionUtils.isNotEmpty(searchDataReqDTO.getCopyrightIds())) {
filterBuilder.must(new MatchQueryBuilder("copyrightId", searchDataReqDTO.getCopyrightIds().stream().collect(Collectors.joining(","))));
}
一,依赖
依赖这块,springboot的版本2.0.9.RELEASE和2.2.5.RELEASE都启动出现异常,后来使用2.3.0.RELEASE就可以启动,2.1.14.RELEASE也可以。
但是实际启动发现es的客户端和服务端的版本不匹配,因为连接了本地。。。后来删除了高阶依赖,将nacos的版本调整就可以了读取到配置了。
这里注意不能写版本号,让系统自己找到合适的版本。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置
项目的
spring.data.elasticsearch.name.cluster-name=elasticsearch
spring.data.elasticsearch.name.cluster‐nodes=10.88.130.97:9300
spring.data.elasticsearch.name.local=true
spring.data.elasticsearch.name.repositories.enable=true
management.endpoint.health.show-details=always
实际上操作发现不对,然后根据网上给的继续配置,依旧不对,老是连接127.0.0.1,
最后将高阶的依赖删除,将nacos的版本降低,就可以了。具体配置如下
#spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=10.88.130.97:9300
spring.data.elasticsearch.repositories.enabled=true
二,实体类
在高版本中会发现type已经过时,入库后发现实际上type是_doc
@Document(indexName = "test",type = "base")
public class User {
@Id
private Long id;
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Text)
private String number;
@Field(type = FieldType.Double)
private BigDecimal price;
@Field(type = FieldType.Integer)
private Integer age;
@Field(type = FieldType.Date)
private Date createTime;
@Field(type = FieldType.Keyword)
private String updateTime;
}
关于index和type
实体类可以决定index和type,切换index是消耗资源的,但是如果是使用了多个type,也是存在一个问题,虽然可以定义不同的字段,但是很明显,因为es底层高效检索的设计,一个type中存在,另一个type中不存在的时候,会在另一个的实体中分配虚拟字段,这就导致两个问题,如果字段区别大导致所有的存储都内存消耗变大,另外是相同的名字,字段类型必须保持一致,否则启动会报错。后期版本的es逐渐弱化type
参考:http://t.zoukankan.com/hanks-p-12041514.html
关于字段
text,key,long,integer,double,都是默认建立索引,注意date默认没有索引
text和key都是针对string类型,但是text是分词后建立索引,key是直接建立索引的,所以尽量使用key,如果是大文件就使用text。
Array是数组
object是json的nested 类型
join是父子关系
参考:https://www.cnblogs.com/gscq073240/articles/9533629.html
/**
* 表示该字段是一个文本,并作最大程度拆分,默认建立索引
*/
@Field(type=FieldType.Text, analyzer="ik_max_word")
/**
* 表示该字段是一个文本,不建立索引
*/
@Field(type=FieldType.Text,index=false)
/**
* 表示该字段是一个文本,日期类型,默认不建立索引
*/
@Field(type=FieldType.Date)
/**
* 表示该字段是一个长整型,默认建立索引
*/
@Field(type=FieldType.Long)
/**
* 表示该字段内容是一个文本并作为一个整体不可分,默认建立索引
*/
@Field(type=FieldType.Keyword)
/**
* 表示该字段内容是一个浮点类型并作为一个整体不可分,默认建立索引
*/
@Field(type=FieldType.Float)
date 、float、long都是不能够被拆分的
关系表查询
关系表查询的方式
1,应用层join,采用多次查询
2,嵌套查询,采用一个doc上存储多个nested 类型的数据,通俗的说就是数据库多张表的字段挤在一个es doc上。数据冗余
3,父子关系,查询速度慢,后期版本的es逐渐用join字段取代父子关系。
查询接口
Long是id的类型
这个是springboot默认的数据库操作,携带了便捷的方法。
public interface UserDao extends ElasticsearchRepository<User,Long> {
}
执行增删改查
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public UserDO add(UserDO user) {
user.setCreateTime(new Date());
UserDO save = userDao.save(user);
return save;
}
@Override
public boolean addList(List<UserDO> list) {
Iterable<UserDO> userDOS = userDao.saveAll(list);
Iterator<UserDO> iterator = userDOS.iterator();
ArrayList<UserDO> re = new ArrayList<>();
while (iterator.hasNext()) {
UserDO next = iterator.next();
re.add(next);
}
log.info("result:{}", re);
return re.size() > 0;
}
@Override
public Iterable delete(String content) {
//先查找拿到iterable
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery(UserDO.FIELD_NAME, content));
Iterable<UserDO> iterable = userDao.search(boolQueryBuilder);
//然后根据iterable进行删除操作
userDao.deleteAll(iterable);
return iterable;
}
@Override
public UserDO update(UserDO user) {
//不存在更新,因为更新就必须知道原来的id,然后执行覆盖操作
UserDO save = userDao.save(user);
return save;
}
@Override
public List<UserDO> search(String content) {
//先查找拿到iterable
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery(UserDO.FIELD_NAME, content));
Iterable<UserDO> iterable = userDao.search(boolQueryBuilder);
Iterator<UserDO> iterator = iterable.iterator();
ArrayList<UserDO> re = new ArrayList<>();
while (iterator.hasNext()) {
UserDO next = iterator.next();
re.add(next);
}
return re;
}
}
// 原生的查询条件类
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 匹配所有记录
//nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
// 查询条件构造器
BoolQueryBuilder builder = QueryBuilders.boolQuery();
BoolQueryBuilder sholdBuilderProd = QueryBuilders.boolQuery();
// 用途值模糊搜索
sholdBuilderProd.should(QueryBuilders.matchPhraseQuery("purposeValue", searchContent));
builder.must(sholdBuilderProd);
BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery();
filterBuilder.must(new MatchQueryBuilder("resourceDesigner",
String.join(",", searchDataReqDTO.getResourceDesignerIds().stream().collect(Collectors.joining(",")))));
filterBuilder.must(QueryBuilders.termsQuery("updaterUserId",searchDataReqDTO.getUpdaterUserIds()));
builder.must(filterBuilder);
builder.filter(QueryBuilders.rangeQuery("weightStart").gte(searchDataReqDTO.getMinWeight()));
nativeSearchQueryBuilder.withQuery(builder);
nativeSearchQueryBuilder.withFilter(builder);
// 排序规则: 按搜索匹配度从高到低排序(名称匹配权重最高)
nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort());
// ES分页从0开始
PageRequest pageRequest = null;
if (searchDataReqDTO.getPage() != null) {
pageRequest = PageRequest.of((int) searchDataReqDTO.getPage().getPageNum() - 1, (int) searchDataReqDTO.getPage().getPageSize());
} else {
pageRequest = PageRequest.of(0, 50);
}
nativeSearchQueryBuilder.withPageable(pageRequest);
// 执行查询
NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
Page<ResourceSearchData> resourceSearchData = iResourceSearchDataRepository.search(searchQuery);
springboot集成不被支持
参考:https://blog.csdn.net/weixin_44600430/article/details/117203834
本地启动的es是7版本的,依赖并没有控制es的版本,加载的是7版本的依赖,在执行方法的时候,会发现search方法已经过时了。