为何要用ElasticSearch
在最近的项目开发中,逐步接触到海量数据的搜索和可视化处理,Elasticsearch 是一个分布式、可扩展、实时的搜索与数据分析引擎。 它建立在一个全文搜索引擎库Apache Lucene基础之上,但隐藏了 Lucene中复杂的细节,使用ElasticSearch可以更高效的实现数据的搜索、分析和探索。Elasticsearch 不仅仅可以实现全文搜索还可以结构化搜索、数据分析、复杂的人类语言处理、地理位置和对象间关联关系等。 通过利用ElasticSearch的水平伸缩性,建立数据模型,并配置监控集群,将海量数据可实时分析,可视化。ES具有以下的特点:
分布式文件存储,并将每一个字段都编入索引,使其可以实时搜索。
速度和性能高,实时分析的分布式搜索引擎。全文搜索,结构化搜索,数据分析,ELKB数据可视化,和传统的数据库相比,它可以很快速的处理海量数据实现各种复杂的数据统计和搜索
可扩展性高,支持PB级别海量数据分布式存储,支持数据分片,可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
ElasticSearch搜索为什么会更快?
其一、因为ElasticSearch提供了强大的索引来提高搜索性能,Elasticsearch使用的倒排索引比关系型数据库的B-Tree索引快
时间序列数据库分为两类,
第一类的数据库按照关系型数据库
[metric_name] [timestamp] [value]
另外一类数据库其表结构是:
[timestamp] [d1] [d2] .. [dn] [v1] [v2] .. [vn]
ElasticSearch采用的正是倒排索引,在插入数据的同时,Elasticsearch还默默的为这些字段建立倒排索引,建立这些索引使得搜索变得高效快速,我们将建立的这些称为term,Elasticsearch为了能快速找到某个term,将所有的term排个序,二分法查找term,logN的查找效率,就像通过字典查找一样,这就是Term Dictionary,同时为了避免term dictionary过大,通过Term Index进行快速查找。当然,同时也会让数据的插入和修改操作效率变得更低,但是ElasticSearch的优势是传统数据库查询无法比拟的
其二、将磁盘里的东西尽量搬进内存,减少磁盘随机读取次数(同时也利用磁盘顺序读特性),结合压缩算法使用内存。
所以,对于使用Elasticsearch进行索引时需要注意:
不需要索引的字段,一定要明确定义出来,因为默认是自动建索引的
同样的道理,对于String类型的字段,不需要analysis的也需要明确定义出来,因为默认也是会analysis的
选择有规律的ID很重要,随机性太大的ID(比如java的UUID)不利于查询
ElasticSearch的应用场景
可以把Elasticsearch作为传统数据库的一个补充,比如全文检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理以及数据可视化,分布式日志数据搜索和分析等等;
例子:
维基百科搜素
The Guardian(国外新闻网站)
Stack Overflow(国外的程序异常讨论论坛)
GitHub(开源代码管理)
电商搜索系统
日志数据分析 ELK
商品价格数据监控
BI系统
站内搜索
使用SpringBoot操作ElasticSearch
引入相关依赖
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.0.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.0.1</version>
</dependency>
通过ElasticSearch官方提供的客户端进行操作
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost(ips[0],port,"http"),
new HttpHost(ips[1],port,"http"),
new HttpHost(ips[0],port,"http")
));
//向ElasticSearch添加文档
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("username",people.getUsername());
jsonMap.put("age", people.getAge());
jsonMap.put("job", people.getJob());
//创建并组装请求
String uuId=UUIdUtils.getUUId();
IndexRequest indexRequest = new IndexRequest("index01")
.id(uuId).source(jsonMap);
//定义监听器
ActionListener listener=new ActionListener() {
@Override
public void onResponse(Object o) {
//正确响应执行的方法
System.out.println("成功添加文档到索引库");
}
@Override
public void onFailure(Exception e) {
System.out.println("添加文档到索引库失败");
}
};
//添加文档
client.indexAsync(indexRequest,RequestOptions.DEFAULT,listener);
//查询
String index="index01";
//创建索引库的搜索请求对象
SearchRequest searchRequest=new SearchRequest(index);
//设置请求对象参数
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
searchRequest.source(searchSourceBuilder);
//建立客户端连接,根据请求对象搜索并获取搜索响应结果
SearchResponse searchResponse=client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits=searchResponse.getHits().getHits();
当然这只是非常简单的操作,在工作中的项目开发可以根据项目的需求进行设计和封装,提高系统的可用性以及对大量并发请求的支持。