第一节 Elasticsearch入门
运行es时报了 error downloading geoip database 错误,版本为8.5.3,jdk为17
"error downloading geoip database" 是Elasticsearch在下载GeoIP数据库时遇到的错误。
在Elasticsearch中,GeoIP功能也可以通过GeoIP数据库提供地理位置信息。当Elasticsearch尝试下载GeoIP数据库时,可能会遇到以下情况:
-
网络连接问题:可能是由于网络连接故障,Elasticsearch无法成功下载GeoIP数据库。请确保网络连接正常,或尝试重新执行下载操作。
-
下载源不可用:Elasticsearch使用的下载源(如MaxMind)可能当前不可用或发生了变化。请检查Elasticsearch的配置文件或插件设置,以确保指定的下载源是有效的。
要解决该问题,你可以尝试以下几个步骤:
-
检查网络连接:确保你的网络连接正常,能够正常访问互联网。你可以尝试打开其他网页或使用其他网络工具来验证网络连接是否正常。
-
更新配置或插件设置:检查Elasticsearch的配置文件或相关插件的设置。确保所使用的下载源是有效的,并且Elasticsearch可以正常访问该下载源。如果下载源发生了变化,你可能需要更新配置文件或插件设置中的URL或下载命令。
粗暴的解决方案是不使用GeoIP功能 :
elasticsearch.yml
配置文件中添加如下配置
ingest.geoip.downloader.enabled: false
WARN ][o.e.x.s.t.n.SecurityNetty4HttpServerTransport] [DESKTOP-AC8IJEV] received plaintext htt
p traffic on an https channel, closing connection Netty4HttpChannel{localAddress=/[0:0:0:0:0:0:0:1]:9200, remoteAddress=
/[0:0:0:0:0:0:0:1]:12271}
因为es默认有安全设置,测试请求不满足,被转发掉了
elasticsearch.yml中更改security为false如下
第二节 Spring整合ES
引入依赖,配置cluster-name, cluster-nodes,使用ElasticsearchTemplate,ElasticsearchRepository来操作ES。
第一步引入依赖
第二步由于我使用的SpringBoot为3.x(Spring6),es为8.5.3,故与教程配置不同。参考
@Configuration
public class ElasticsearchConfig extends ElasticsearchConfiguration {
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo("localhost:9200")
//9200 http请求, 9300 tcp请求 ,服务器一般使用tcp访问ES
.build();
}
}
第三步使用的是使用 Elasticsearch Operations 和 Elasticsearch Repository 来操作es数据库
对于简单的操作使用Elasticsearch Repository
1. 首先对操作的数据实体对象进行配置(数据绑定
@Document(indexName = "discusspost")
public class DiscussPost {
@Id
private int id;
@Field(type = FieldType.Integer)
private int userId;
// 互聯網校招 analyzer = 保存時將一句話拆分為更多的單詞的分詞器, 搜索時 使用另外一個 分詞可能少,滿足搜索意圖的分詞器
@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;
}
2. 然后创建操作的interface 继承 ElasticsearchRepository (DiscussPostRepository为接下来的操作对象
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {
}
操作数据库前:
@Autowired
private DiscussPostRepository discussPostRepository;
@Autowired
private ElasticsearchOperations elasticsearchOperations;
简单操作
1.单个增加(save
discussPostRepository.save(discussPostMapper.selectDiscussPostById(241));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(242));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(243));
2.列表增加
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(101,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(102,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(103,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(111,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(112,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(131,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(132,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(133,0,100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(134,0,100));
3.改动(重新save
DiscussPost discussPost = discussPostMapper.selectDiscussPostById(231);
discussPost.setContent("我是新人,使勁灌水");
discussPostRepository.save(discussPost);
4.删除
public void testDelete(){
// discussPostRepository.deleteById(231);
discussPostRepository.deleteAll();
}
对于复杂的搜索则使用了 Elasticsearch Operations
查询语句和高亮
@Test
public void testSearchByRepository(){
/*高亮的fieldList创建*/
List<HighlightField> fields = new ArrayList<>();
fields.add(new HighlightField("title"));
fields.add(new HighlightField("content"));
//这几个lambda表达式看的头疼
NativeQuery query = new NativeQueryBuilder()
.withQuery(
/*创建一个Query */
q-> q.multiMatch(m -> m.query("互联网寒冬").fields("title", "content"))
).withSort(s -> s.field(m->m.field("type").order(SortOrder.Desc)))
.withSort(s -> s.field(m->m.field("score").order(SortOrder.Desc)))
.withSort(s -> s.field(m->m.field("createTime").order(SortOrder.Desc)))
.withPageable(PageRequest.of(0,10))
.withHighlightQuery(new HighlightQuery
(new Highlight(new HighlightParameters.HighlightParametersBuilder().withPreTags("<em>").withPostTags("</em>").build() , fields) , DiscussPost.class))
.build();
SearchHits<DiscussPost> searchHits = elasticsearchOperations.search(query, DiscussPost.class);
System.out.println("一共有" + searchHits.getTotalHits()+ "条数据");
SearchPage<DiscussPost> page = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
System.out.println("当前是第"+page.getNumber()+"页");
System.out.println("当前页有多少数据"+ page.getNumberOfElements());
System.out.println("共有多少页"+page.getTotalPages());
for(SearchHit<DiscussPost> searchHit: page){
System.out.println(searchHit.getContent().toString());
}
//高亮替换掉原内容
for(SearchHit<DiscussPost> searchHit: page){
List<String> a = searchHit.getHighlightField("title");
List<String> b = searchHit.getHighlightField("content");
if(a != null){
searchHit.getContent().setTitle(String.join("",a));
}
if(b != null){
searchHit.getContent().setContent(String.join("",b));
}
}
//查看是否替换
for(SearchHit<DiscussPost> searchHit: page){
System.out.println(searchHit.getContent().toString());
}
}
参考官网: spring-data/elasticsearch
applications using Spring Data Elasticsearch normally use the higher level abstractions of Elasticsearch Operations and Elasticsearch Repositories.
根据官网,当前版本有两种客户端Client配置
1. Imperative rest client, 2. Reactive Rest Client 这两种客户端的关系:
Imperative Rest Client和Reactive Rest Client是两种不同的RESTful API客户端编程风格,主要区别如下:
-
编程模型
- Imperative:使用阻塞式编程模型进行同步调用,会等待服务器返回响应,并阻塞当前线程。
- Reactive:使用非阻塞式编程模型进行异步调用,可以处理更高并发请求。
-
响应处理
- Imperative:将响应体作为返回值返回,需要开发人员自己处理异常、错误状态码等情况。
- Reactive:将响应体包装在流或Mono/Flux对象中返回,可以使用丰富的响应式操作符来处理数据流。
-
并发性
- Imperative:每个请求都需独占一个线程,开销较大,在高并发环境下可能存在性能问题。
- Reactive:使用事件循环和异步操作来实现高并发性能,对系统资源利用更加高效。
联系:
- 两者都是用于与RESTful API进行交互的客户端。
- 都支持对HTTP请求和响应进行序列化和反序列化。
- 都支持根据API规范生成客户端代码来简化开发。
选择使用Imperative Rest Client还是Reactive Rest Client取决于应用程序的需求和偏好。如果应用程序需要高并发性能,那么Reactive Rest Client可能更适合,因为Reactive Rest Client使用异步方式处理请求和响应,可以更加高效地利用系统资源。如果应用程序更喜欢同步编程模型,那么Imperative Rest Client可能会更适合,因为它的代码更为简单,易于理解和维护。
高并发,异步处理请求和响应使用Reactive Rest Client
同步处理使用Imperative Rest Client
第三章 开发社区搜索功能
功能如下: