1 . ElasticSearch(简称ES)
- ES即为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案,其第一个版本于2010年2月出现在GitHub上并迅速成为最受欢迎的项目之一。
首先,ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎。
ES也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTful
API来隐藏Lucene的复杂性,从而让全文搜索变得简单。 不过,ES的核心不在于Lucene,其特点更多的体现为:
分布式的实时文件存储,每个字段都被索引并可被搜索 分布式的实时分析搜索引擎 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
高度集成化的服务,你的应用可以通过简单的 RESTful API、各种语言的客户端甚至命令行与之 交互。
上手Elasticsearch非常容易。它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它拥有开瓶即饮的效果(安装即可使用),只需很少的学习既可在生产环境中使用。
2. ES的使用者及类似框架
-
典型使用案例
①Github使用Elasticsearch搜索20TB的数据,包括13亿的文件和1300亿行的代码.
②Foursquare实时搜索5千万地点信息?Foursquare每天都用Elasticsearch做这样的事.
③德国SoundCloud使用Elasticsearch来为1.8亿用户提供即时精准的音乐搜索服务.
④Mozilla公司以火狐著名,它目前使用 WarOnOrange 这个项目来进行单元或功能测试,测试的结果以 json的方式索引到elasticsearch中,开发人员可以非常方便的查找 bug.
⑤Sony公司使用elasticsearch 作为信息搜索引擎. -
类似框架
① Solr(重量级对手)
Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。
Solr和ES比较:
Solr 利用 Zookeeper 进行分布式管理,支持更多格式的数据(HTML/PDF/CSV),官方提供的功能更多在传统的搜索应用中表现好于 ES,但实时搜索效率低。
ES自身带有分布式协调管理功能,但仅支持json文件格式,本身更注重于核心功能,高级功能多有第三方插件提供,在处理实时搜索应用时效率明显高于 ES。
② Katta
基于 Lucene 的,支持分布式,可扩展,具有容错功能,准实时的搜索方案。
优点:开箱即用,可以与 Hadoop 配合实现分布式。具备扩展和容错机制。
缺点:只是搜索方案,建索引部分还是需要自己实现。在搜索功能上,只实现了最基本的需求。成功案例较少,项目的成熟度稍微差一些。
③ HadoopContrib
Map/Reduce 模式的,分布式建索引方案,可以跟 Katta 配合使用。
优点:分布式建索引,具备可扩展性。
缺点:只是建索引方案,不包括搜索实现。工作在批处理模式,对实时搜索的支持不佳。
3.安装ES
-
ES服务只依赖于JDK,推荐使用JDK1.7+。
① 下载ES安装包
官方下载地址:https://www.elastic.co/downloads/elasticsearch
本课程以在window环境下,ES 5.2.2版本为例,下载对应的ZIP文件
② 运行ES
bin/elasticsearch.bat
③ 验证
访问:http://localhost:9200/
看到上图信息,恭喜你,你的ES集群已经启动并且正常运行.
3.java 操作 es 增删查改
ES对Java提供一套操作索引库的工具包,即Java API。所有的ES操作都使用Client对象执行。
ES的Maven引入
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
// 返回es java客户端
public TransportClient getClient() throws Exception {
// on startup
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
return client;
}
// 增
@Test
public void testAdd() throws Exception {
TransportClient client = getClient();
Map<String, Object> source = new HashMap<String, Object>();
source.put("id", "1");
source.put("price", 5000);
source.put("gj", "cn");
IndexResponse indexResponse = client.prepareIndex("shop", "goods", "1").setSource(source).get();
System.out.println(indexResponse);
}
// 删除
@Test
public void testDelete() throws Exception {
TransportClient client = getClient();
DeleteResponse deleteResponse = client.prepareDelete("shop", "goods", "1").get();
System.out.println(deleteResponse);
}
// 改
@Test
public void testUpdate() throws Exception {
TransportClient client = getClient();
Map<String, Object> source = new HashMap<String, Object>();
source.put("id", "1");
source.put("price", 6000);
source.put("gj", "cn");
UpdateResponse updateResponse = client.prepareUpdate("shop", "goods", "1").setDoc(source).get();
System.out.println(updateResponse);
}
// save or update 如果文档有的话就修改,没有就新增
@Test
public void saveorupdate() throws Exception {
TransportClient client = getClient();
Map<String, Object> source = new HashMap<String, Object>();
source.put("id", "1");
source.put("price", 7000);
source.put("gj", "cn");
IndexRequest indexRequest = new IndexRequest("shop", "goods", "1").source(source);
UpdateRequest updateRequest = new UpdateRequest("shop", "goods", "1").doc(source).upsert(indexRequest);
client.update(updateRequest).get();
}
// 查
@Test
public void testQuery() throws Exception {
TransportClient client = getClient();
GetResponse getResponse = client.prepareGet("shop", "goods", "1").get();
System.out.println(getResponse.getSource());
}
// 批量 同步数据库的数据到我们的索引库里面去
@Test
public void testBulk() throws Exception {
TransportClient client = getClient();
// 构建了请求批量对象
BulkRequestBuilder bulkRequest = client.prepareBulk();
for (int i = 0; i < 10; i++) {
// 增加数据
Map<String, Object> source = new HashMap<String, Object>();
source.put("id", i);
source.put("name", "iphone");
source.put("price", 10 * i + i);
source.put("gj", "cn");
bulkRequest.add(client.prepareIndex("shop", "goods", i + "").setSource(source));
}
// 提交数据请求
BulkResponse bulkResponse = bulkRequest.get();
if (bulkResponse.hasFailures()) {
System.out.println("出错误了");
}
}
// 查询
/* # 找出 名为 iphone 然后 价格范围为 [5000-9000] 发行国家:cn 分页数1 每页显示2条 按价格降序
#select *from goods where gj=cn and 5000<price<9000*/
@Test
public void testSearch() throws Exception {
// 获取客户端对象
TransportClient client = getClient();
// 查询对象
//BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 必须查询对象 关键字匹配对象
boolQueryBuilder.must(new MatchQueryBuilder("name", "iphone"));
// 过滤对象
List<QueryBuilder> filter = boolQueryBuilder.filter();
filter.add(new TermQueryBuilder("gj", "cn"));
filter.add(new RangeQueryBuilder("price").gte(20).lte(40));
// GET shop/goods/_search
SearchResponse searchResponse = client.prepareSearch("shop").setTypes("goods").setQuery(boolQueryBuilder).setFrom(0).setSize(2).addSort("price", SortOrder.DESC).get();
SearchHits hits = searchResponse.getHits();
System.out.println("查询总数:"+hits.totalHits());
// 获取真实的数据数组
SearchHit[] hits2 = hits.hits();
for (SearchHit searchHit : hits2) {
Map<String, Object> source = searchHit.getSource();
System.out.println(source);
}
}