网站小视频怎么做的,网站专题模板下载,招聘网站开发的流程,门户网站的含义上篇解释了 ES 的基本概念和分词器。Elastic Search #xff08;ES#xff09;Java 入门实操#xff08;1#xff09;下载安装、概念-CSDN博客
Elastic Search#xff08;ES#xff09;Java 入门实操#xff08;3#xff09;数据同步-CSDN博客
这篇主要演示 Java 整合…上篇解释了 ES 的基本概念和分词器。Elastic Search ESJava 入门实操1下载安装、概念-CSDN博客
Elastic SearchESJava 入门实操3数据同步-CSDN博客
这篇主要演示 Java 整合 ES进行数据搜索。
ES 实现搜索接口
首先根据 MySQL 字段在 ES 创建索引。
create table mydb
(id int auto_increment comment 序号primary key,title varchar(20) not null comment 标题,content text not null comment 内容,cretateTime datetime default CURRENT_TIMESTAMP not null comment 创建时间,updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment 更新时间,isDelete tinyint default 0 not null comment 是否删除
)comment 文章 collate utf8mb4_unicode_ci;
PUT article_1
{aliases: { #别名article: {}},mappings: {properties: {title: {type: text, #字段类型analyzer: ik_max_word,#插入时分词方式search_analyzer: ik_smart, #查询时分词方式fields: { #字段配置子字段keyword: { type: keyword, #精确匹配ignore_above: 256 #超过 256 字符就忽略查询}}},content: {type: text,analyzer: ik_max_word,search_analyzer: ik_smart,fields: {keyword: {type: keyword,ignore_above: 256}}},createTime: {type: date},updateTime: {type: date},isDelete: {type: keyword}}}
}
引入 spring-data-elasticsearch 依赖
需要注意版本号一定要兼容
Spring Data Elasticsearch - Reference Documentation 这里使用的是 7.17版本所以选择相近的 4.4.x版本的 依赖同样的 springboot 的版本也得严格对应。Maven Repository: org.springframework.data » spring-data-elasticsearch » 4.4.7 (mvnrepository.com) 下面的报错就是版本不对需要把springboot 改为 2.7
java.lang.NoSuchFieldError: INDEX_CONTENT_TYPE
!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-elasticsearch --
dependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-elasticsearch/artifactIdversion4.4.7/version
/dependency启动 springboot有调用的日志 给 ES 索引创建实体类
/*** ES 实体类* document 注解是将Java 对象映射到 Elasticsearch 索引和类型中*/
Document(indexName article)
Data
public class ArticleEsDto implements Serializable {private static final String DATE_TIME_PATTERN yyyy-MM-ddTHH:mm:ss.SSSZ;/*** id* 需要打上 id 注解指定 ES 中存储的 id 是唯一字段* 如果新增是不传入则 ES 会自动生成*/Idprivate long id;/*** 标题*/private String title;/*** 内容*/private String content;/*** 创建时间*/Field(index false, store true,type FieldType.Date,format {},pattern DATE_TIME_PATTERN)private Date createTime;/*** 更新时间* Field这是一个MyBatis-Plus注解用于标注该字段在数据库表中的对应关系。* 其中index false表示该字段不在数据库表的索引中* store true表示该字段在数据库表的存储中* type FieldType.Date表示该字段的类型为Date* format {}表示该字段的格式为空* pattern DATE_TIME_PATTERN表示该字段的日期时间格式为DATE_TIME_PATTERN。*/Field(index false, store true,type FieldType.Date,format {},pattern DATE_TIME_PATTERN)private Date updateTime;/*** 是否删除*/private Integer isDelete;private static final long serialVersionUID 1L;
}
第一种方式
elasticsearch Respository新建类继承该类默认提供了简单的增删改查方法多用于可以预期的相对不复杂的查询
NoRepositoryBean
public interface CrudRepositoryT, ID extends RepositoryT, ID {S extends T S save(S entity);S extends T IterableS saveAll(IterableS entities);OptionalT findById(ID id);boolean existsById(ID id);IterableT findAll();IterableT findAllById(IterableID ids);long count();void deleteById(ID id);void delete(T entity);void deleteAllById(Iterable? extends ID ids);void deleteAll(Iterable? extends T entities);void deleteAll();
}
/*** ES 的控制层* 继承 ElasticsearchRepository 即可*/
public interface ArticleEsDao extends ElasticsearchRepositoryArticleEsDto, Long {// 这里可以扩展一些自定义方法// 例如根据标题模糊查询ListArticleEsDto findByTitle(String title);}
新增测试
//注入接口Resourceprivate ArticleEsDao articleEsDao;//测试新增Testvoid EsTest1(){//创建实体对象并添加属性ArticleEsDto articleEsDto new ArticleEsDto();articleEsDto.setId(1L);articleEsDto.setTitle(青花瓷);articleEsDto.setContent(天青色等烟雨而我在等你);articleEsDto.setCreateTime(new Date());articleEsDto.setUpdateTime(new Date());articleEsDto.setIsDelete(0);//调用方法保存articleEsDao.save(articleEsDto);System.out.println(articleEsDto.getId());}
dev tools 查看
GET article/_search/ 自定义方法测试
我们在上面创建接口的时候创建了一个根据标题查询的方法 Testvoid EsTest2(){ListArticleEsDto articleEsDtos articleEsDao.findByTitle(青花瓷);System.out.println(articleEsDtos);} 第二种方式
spring 默认提供了操作 ES 的客户端对象 ElasticSearchRestTemplate同样提供了增删改查更加灵活适用于更加复杂的操作返回结果更加完整但是需要自己解析。 Resourceprivate ElasticsearchRestTemplate elasticsearchRestTemplate;
提示在编写查询条件以及处理数据时可以先在 Dev Tools 中执行一下查询没问题之后再进行代码层面的条件编写。
查询 DSL
官方文档Query and filter context | Elasticsearch Guide [8.14] | Elastic
查询模式Boolean query | Elasticsearch Guide [8.14] | Elastic
GET /_search
{query: { bool: { //组合条件must: [ //必须匹配{ match: // 模糊匹配{ title: Search }},{ match: { content: Elasticsearch }}],filter: [ //{ term: //精确匹配 { status: published }},{ range: //范围匹配 { publish_date: { gte: 2015-01-01 }}}]}}
}
除了 must filter还有 must_not必须不存在才能匹配should至少有多少个条件相符才匹配同时还有一个参数 minimum_should_match 满足最小的条件数比如 1至少满足一个条件才能查询到比如标题和描述存在一个就可以返回结果。
POST _search
{query: {bool : {must : {term : { user.id : kimchy }},filter: {term : { tags : production }},must_not : {range : {age : { gte : 10, lte : 20 }}},should : [{ term : { tags : env1 } },{ term : { tags : deployed } }],minimum_should_match : 1,boost : 1.0}}
} 需要注意的是通过模糊查询之后查询结果中有一个参数是 max_score表示这条数据和搜索条件的最高匹配度。
在 Java 中编写查询条件以及处理查询的数据。
主要使用到的 API
//查询条件构造器
BoolQueryBuilder boolQueryBuilder QueryBuilders.boolQuery();//排序条件构造器
SortBuilder? sortBuilder SortBuilders.scoreSort();//分页
PageRequest pageRequest PageRequest.of((int) current, (int) pageSize);//组合查询条件
NativeSearchQuery searchQuery new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withPageable(pageRequest).withSorts(sortBuilder).build();
//调用 elasticsearchRestTemplate 查询
SearchHitsPostEsDTO searchHits elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);完整代码
/*** 从 es 查询数据*/
Service
public class ArticleEsManager {Resourceprivate ArticleMapper articleMapper;Resourceprivate ElasticsearchRestTemplate elasticsearchRestTemplate;public PageArticle searchByEs(ArticleQueryRequest articleQueryRequest) {//提取查询参数Long id articleQueryRequest.getId();String searchText articleQueryRequest.getSearchText();String content articleQueryRequest.getContent();String title articleQueryRequest.getTitle();//设置分页参数起始页为 0int current articleQueryRequest.getCurrent() -1 ;int pageSize articleQueryRequest.getPageSize();String sortField articleQueryRequest.getSortField();String sortOrder articleQueryRequest.getSortOrder();//构建布尔查询创建 boolqueryBuilder用于后续查询条件构建BoolQueryBuilder boolQueryBuilder QueryBuilders.boolQuery();//过滤查询条件//过滤掉被逻辑删除的 term 是精确匹配boolQueryBuilder.filter(QueryBuilders.termQuery(isDelete,0));//id必须精确匹配if(id!null){boolQueryBuilder.filter(QueryBuilders.termQuery(id,id));}//模糊查询按照查询词关键词检索if(StringUtils.isNotEmpty(searchText)){boolQueryBuilder.should(QueryBuilders.matchQuery(title,searchText));boolQueryBuilder.should(QueryBuilders.matchQuery(content,searchText));//设置至少多少匹配才进行查询boolQueryBuilder.minimumShouldMatch(1);}//根据标题检索if(StringUtils.isNotEmpty(title)){boolQueryBuilder.should(QueryBuilders.matchQuery(title,title));boolQueryBuilder.minimumShouldMatch(1);}//根据内容检索if(StringUtils.isNotEmpty(content)){boolQueryBuilder.should(QueryBuilders.matchQuery(content,searchText));//设置至少多少匹配才进行查询boolQueryBuilder.minimumShouldMatch(1);}//进行排序//对查询结果的分数进行排序SortBuilder? sortBuilder SortBuilders.scoreSort();if (StringUtils.isNotEmpty(sortField) StringUtils.isNotEmpty(sortOrder)){sortBuilder SortBuilders.fieldSort(sortField);sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC:SortOrder.DESC);}//分页PageRequest pageRequest PageRequest.of(current, pageSize);//构造查询NativeSearchQuery searchQuery new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withPageable(pageRequest).withSorts(sortBuilder).build();//调用 elasticsearchRestTemplate 执行查询SearchHitsArticleEsDto searchHits elasticsearchRestTemplate.search(searchQuery, ArticleEsDto.class);System.out.println(searchHits);PageArticle page new Page();page.setTotal(searchHits.getTotalHits());//新建集合存储文章ListArticle resourceList new ArrayList();//处理结果判断是否有搜索结果if(searchHits.hasSearchHits()){//获取结果列表ListSearchHitArticleEsDto searchHits1 searchHits.getSearchHits();System.out.println(searchHits1);//获取结果的id使用id在数据库中查询ListLong ids searchHits1.stream().map(searchHit - searchHit.getContent().getId()).collect(Collectors.toList());ListArticle articles articleMapper.selectBatchIds(ids);//将查询结果与数据库查询结果进行匹配if (CollectionUtils.isNotEmpty(articles)) {//将查询结果与数据库查询结果进行匹配MapLong, ListArticle collect articles.stream().collect(Collectors.groupingBy(Article::getId));//遍历文章idarticles.forEach(articleId - {if(collect.containsKey(articleId)){resourceList.add(collect.get(articleId).get(0));}else{// 从 es 清空 db 已物理删除的数据String delete elasticsearchRestTemplate.delete(String.valueOf(articleId), ArticleEsDto.class);}});}}page.setRecords(resourceList);return page;}
}
成功查询到数据 完整代码
/*** 从 es 查询数据*/
Service
public class ArticleEsManager {Resourceprivate ArticleMapper articleMapper;Resourceprivate ElasticsearchRestTemplate elasticsearchRestTemplate;public PageArticle searchByEs(ArticleQueryRequest articleQueryRequest) {//提取查询参数Long id articleQueryRequest.getId();String searchText articleQueryRequest.getSearchText();String content articleQueryRequest.getContent();String title articleQueryRequest.getTitle();//设置分页参数起始页为 0int current articleQueryRequest.getCurrent() -1 ;int pageSize articleQueryRequest.getPageSize();String sortField articleQueryRequest.getSortField();String sortOrder articleQueryRequest.getSortOrder();//构建布尔查询创建 boolqueryBuilder用于后续查询条件构建BoolQueryBuilder boolQueryBuilder QueryBuilders.boolQuery();//过滤查询条件//过滤掉被逻辑删除的 term 是精确匹配boolQueryBuilder.filter(QueryBuilders.termQuery(isDelete,0));//id必须精确匹配if(id!null){boolQueryBuilder.filter(QueryBuilders.termQuery(id,id));}//模糊查询按照查询词关键词检索if(StringUtils.isNotEmpty(searchText)){boolQueryBuilder.should(QueryBuilders.matchQuery(title,searchText));boolQueryBuilder.should(QueryBuilders.matchQuery(content,searchText));//设置至少多少匹配才进行查询boolQueryBuilder.minimumShouldMatch(1);}//根据标题检索if(StringUtils.isNotEmpty(title)){boolQueryBuilder.should(QueryBuilders.matchQuery(title,title));boolQueryBuilder.minimumShouldMatch(1);}//根据内容检索if(StringUtils.isNotEmpty(content)){boolQueryBuilder.should(QueryBuilders.matchQuery(content,searchText));//设置至少多少匹配才进行查询boolQueryBuilder.minimumShouldMatch(1);}//进行排序//对查询结果的分数进行排序SortBuilder? sortBuilder SortBuilders.scoreSort();if (StringUtils.isNotEmpty(sortField) StringUtils.isNotEmpty(sortOrder)){sortBuilder SortBuilders.fieldSort(sortField);sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC:SortOrder.DESC);}//分页PageRequest pageRequest PageRequest.of(current, pageSize);//构造查询NativeSearchQuery searchQuery new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).withPageable(pageRequest).withSorts(sortBuilder).build();//调用 elasticsearchRestTemplate 执行查询SearchHitsArticleEsDto searchHits elasticsearchRestTemplate.search(searchQuery, ArticleEsDto.class);System.out.println(searchHits);PageArticle page new Page();page.setTotal(searchHits.getTotalHits());//新建集合存储文章ListArticle resourceList new ArrayList();//处理结果判断是否有搜索结果if(searchHits.hasSearchHits()){//获取结果列表ListSearchHitArticleEsDto searchHits1 searchHits.getSearchHits();System.out.println(searchHits1);//获取结果的id使用id在数据库中查询ListLong ids searchHits1.stream().map(searchHit - searchHit.getContent().getId()).collect(Collectors.toList());ListArticle articleList articleMapper.selectBatchIds(ids);//将查询结果与数据库查询结果进行匹配if (CollectionUtils.isNotEmpty(articleList)) {//将查询结果与数据库查询结果进行匹配MapLong, ListArticle collect articleList.stream().collect(Collectors.groupingBy(Article::getId));//遍历文章idids.forEach(articleId - {if(collect.containsKey(articleId)){resourceList.add(collect.get(articleId).get(0));}else{// 从 es 清空 db 已物理删除的数据String delete elasticsearchRestTemplate.delete(String.valueOf(articleId), ArticleEsDto.class);}});}}//设置到分页里page.setRecords(resourceList);return page;}