前言

写作于
2022-10-16 17:04:07

发布于
2022-11-21 20:09:28

org.springframework.beans.factory.BeanCreationException

bug

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'discussPostRepository' defined in com.jsss.community.dao.elasticsearch.DiscussPostRepository defined in @EnableElasticsearchRepositories declared on ElasticsearchRepositoriesRegistrar.EnableElasticsearchRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.mapping.MappingException: Property DiscussPost.createTime is annotated with FieldType.Date but has no DateFormat defined
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1794)

错误产生

springboot+es7.6.2

相关资源

package com.jsss.community.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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 java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "discusspost", /*type = "_doc",*/ shards = 6, replicas = 3)
public class DiscussPost {

@Id
private int id;

@Field(type = FieldType.Integer)
private int userId;

// 互联网校招
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String title;

@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String content;

@Field(type = FieldType.Integer)
private int type;

@Field(type = FieldType.Integer)
private int status;

@Field(type = FieldType.Date)
private Date createTime;

@Field(type = FieldType.Integer)
private int commentCount;

@Field(type = FieldType.Double)
private double score;
}

解决

package com.jsss.community.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
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 java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "discusspost", /*type = "_doc",*/ shards = 6, replicas = 3)
public class DiscussPost {

@Id
private int id;

@Field(type = FieldType.Integer)
private int userId;

// 互联网校招
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String title;

@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String content;

@Field(type = FieldType.Integer)
private int type;

@Field(type = FieldType.Integer)
private int status;

@Field(type = FieldType.Date,format = DateFormat.basic_date)
private Date createTime;

@Field(type = FieldType.Integer)
private int commentCount;

@Field(type = FieldType.Double)
private double score;
}

另外

# ElasticsearchProperties 6
#spring.data.elasticsearch.cluster-name=nowcoder
# HTTP TCP
#spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300

# ElasticsearchProperties 7
#spring.elasticsearch.rest.connection-timeout=1s
#spring.elasticsearch.rest.read-timeout=30s
spring.elasticsearch.rest.uris=http://localhost:9200

​https://www.nowcoder.com/study/live/246/6/4​

6.4.1

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {

@Autowired
private DiscussPostMapper discussMapper;

@Autowired
private DiscussPostRepository discussRepository;

@Autowired
private ElasticsearchTemplate elasticTemplate;

@Test
public void testInsert() {
discussRepository.save(discussMapper.selectDiscussPostById(241));
discussRepository.save(discussMapper.selectDiscussPostById(242));
discussRepository.save(discussMapper.selectDiscussPostById(243));
}

@Test
public void testInsertList() {
discussRepository.saveAll(discussMapper.selectDiscussPosts(101, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(102, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(103, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(111, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(112, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(131, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(132, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(133, 0, 100, 0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(134, 0, 100, 0));
}

@Test
public void testUpdate() {
DiscussPost post = discussMapper.selectDiscussPostById(231);
post.setContent("我是新人,使劲灌水.");
discussRepository.save(post);
}

@Test
public void testDelete() {
// discussRepository.deleteById(231);
discussRepository.deleteAll();
}

@Test
public void testSearchByRepository() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.withPageable(PageRequest.of(0, 10))
.withHighlightFields(
new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
).build();

// elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper)
// 底层获取得到了高亮显示的值, 但是没有返回.

Page<DiscussPost> page = discussRepository.search(searchQuery);
System.out.println(page.getTotalElements());
System.out.println(page.getTotalPages());
System.out.println(page.getNumber());
System.out.println(page.getSize());
for (DiscussPost post : page) {
System.out.println(post);
}
}

@Test
public void testSearchByTemplate() {
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.withPageable(PageRequest.of(0, 10))
.withHighlightFields(
new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
).build();

Page<DiscussPost> page = elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
SearchHits hits = response.getHits();
if (hits.getTotalHits() <= 0) {
return null;
}

List<DiscussPost> list = new ArrayList<>();
for (SearchHit hit : hits) {
DiscussPost post = new DiscussPost();

String id = hit.getSourceAsMap().get("id").toString();
post.setId(Integer.valueOf(id));

String userId = hit.getSourceAsMap().get("userId").toString();
post.setUserId(Integer.valueOf(userId));

String title = hit.getSourceAsMap().get("title").toString();
post.setTitle(title);

String content = hit.getSourceAsMap().get("content").toString();
post.setContent(content);

String status = hit.getSourceAsMap().get("status").toString();
post.setStatus(Integer.valueOf(status));

String createTime = hit.getSourceAsMap().get("createTime").toString();
post.setCreateTime(new Date(Long.valueOf(createTime)));

String commentCount = hit.getSourceAsMap().get("commentCount").toString();
post.setCommentCount(Integer.valueOf(commentCount));

// 处理高亮显示的结果
HighlightField titleField = hit.getHighlightFields().get("title");
if (titleField != null) {
post.setTitle(titleField.getFragments()[0].toString());
}

HighlightField contentField = hit.getHighlightFields().get("content");
if (contentField != null) {
post.setContent(contentField.getFragments()[0].toString());
}

list.add(post);
}

return new AggregatedPageImpl(list, pageable,
hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
}
});

System.out.println(page.getTotalElements());
System.out.println(page.getTotalPages());
System.out.println(page.getNumber());
System.out.println(page.getSize());
for (DiscussPost post : page) {
System.out.println(post);
}
}

}

​​SpringBoot整合ElasticSearch7.12实现增删改查及高亮分词查询​​

package com.jsss.community.config;

import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;

@Configuration
public class EsConfig{
//localhost:9200 写在配置文件中就可以了
@Value("${elasticSearch.url}")
private String esUrl;

@Bean
RestHighLevelClient client() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(esUrl)//elasticsearch地址
.build();

return RestClients.create(clientConfiguration).rest();
}
}
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {

@Autowired
private DiscussPostMapper discussMapper;

@Autowired
private DiscussPostRepository discussRepository;

@Qualifier("client")
@Autowired
private RestHighLevelClient restHighLevelClient;

//判断某id的文档(数据库中的行)是否存在
@Test
public void testExist(){
boolean exists =discussRepository.existsById(231);
System.out.println(exists);
}

//一次保存一条数据
@Test
public void testInsert() {
//把id为241的DiscussPost的对象保存到discusspost索引(es的索引相当于数据库的表)
discussRepository.save(discussMapper.selectDiscussPostById(241));
discussRepository.save(discussMapper.selectDiscussPostById(242));
discussRepository.save(discussMapper.selectDiscussPostById(243));
}

//一次保存多条数据
@Test
public void testInsertList() {
//把id为101的用户发的前100条帖子(List<DiscussPost>)存入es的discusspost索引(es的索引相当于数据库的表)
discussRepository.saveAll(discussMapper.selectDiscussPosts(101, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(102, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(103, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(111, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(112, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(131, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(132, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(133, 0, 100,0));
discussRepository.saveAll(discussMapper.selectDiscussPosts(134, 0, 100,0));
}

//通过覆盖原内容,来修改一条数据
@Test
public void testUpdate() {
DiscussPost post = discussMapper.selectDiscussPostById(231);
post.setContent("我是新人,使劲灌水。");
discussRepository.save(post);
}

//修改一条数据
//覆盖es里的原内容 与 修改es中的内容 的区别:String类型的title被设为null,覆盖的话,会把es里的该对象的title也设为null;UpdateRequest,修改后该对象的title不变
@Test
void testUpdateDocument() throws IOException{
UpdateRequest request = new UpdateRequest("discusspost", "109");
request.timeout("1s");
DiscussPost post = discussMapper.selectDiscussPostById(230);
post.setContent("我是新人,使劲灌水.");
post.setTitle(null);//es中的title会保存原内容不变
request.doc(JSON.toJSONString(post), XContentType.JSON);
UpdateResponse updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);
System.out.println(updateResponse.status());
}

//删除一条数据和删除所有数据
@Test
public void testDelete() {
discussRepository.deleteById(231);//删除一条数据
// discussRepository.deleteAll();//删除所有数据
}

//不带高亮的查询
@Test
public void noHighlightQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("discusspost");//discusspost是索引名,就是表名

//构建搜索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
//在discusspost索引的title和content字段中都查询“互联网寒冬”
.query(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
// matchQuery是模糊查询,会对key进行分词:searchSourceBuilder.query(QueryBuilders.matchQuery(key,value));
// termQuery是精准查询:searchSourceBuilder.query(QueryBuilders.termQuery(key,value));
.sort(SortBuilders.fieldSort("type").order(SortOrder.DESC))//置顶
.sort(SortBuilders.fieldSort("score").order(SortOrder.DESC))//价值
.sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))//时间
//一个可选项,用于控制允许搜索的时间:searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
.from(0)// 指定从哪条开始查询
.size(10);// 需要查出的总记录条数

searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

System.out.println(JSONObject.toJSON(searchResponse));

List<DiscussPost> list = new LinkedList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
DiscussPost discussPost = JSONObject.parseObject(hit.getSourceAsString(), DiscussPost.class);
System.out.println(discussPost);
list.add(discussPost);
}
}

//带高亮的查询
@Test
public void highlightQuery() throws Exception{
SearchRequest searchRequest = new SearchRequest("discusspost");//discusspost是索引名,就是表名

//高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.field("content");
highlightBuilder.requireFieldMatch(false);
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");

//构建搜索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
.query(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.sort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
.sort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
.sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.from(0)// 指定从哪条开始查询
.size(10)// 需要查出的总记录条数
.highlighter(highlightBuilder);//高亮

searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

List<DiscussPost> list = new LinkedList<>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
DiscussPost discussPost = JSONObject.parseObject(hit.getSourceAsString(), DiscussPost.class);

// 处理高亮显示的结果
HighlightField titleField = hit.getHighlightFields().get("title");
if (titleField != null) {
discussPost.setTitle(titleField.getFragments()[0].toString());
}
HighlightField contentField = hit.getHighlightFields().get("content");
if (contentField != null) {
discussPost.setContent(contentField.getFragments()[0].toString());
}
System.out.println(discussPost);
list.add(discussPost);
}
}



}