ElasticSearch进阶 ——原生ES深入
目录
## 原生ES相关:
ES结构:5大概念
1.index 索引库
2.type 数据类型,索引库分类
3.document 文档,json格式数据
4.field 文档中key
5.mappings 映射(field值的约束)
其他相关概念:
Near Realtime(NRT):
Elasticsearch是一个几乎实时的搜索平台。即从索引一个文档到这个文档可被搜索只需要一点点的延迟,
这个时间一般以毫秒级为单位。简而言之就是非常快!
Cluster:
ES默认带有集群,而且十分适合进行集群化处理,这已经成为其一大特色。
群集是一个或多个节点(服务器)的集合,这些节点共同保存整个数据,并在所有节点上提供联合索引和搜
索功能。一个集群由一个唯一集群ID确定,并指定一个集群名(默认为“elasticsearch”)。该集群名非常重要,
因为节点可以通过这个集群名加入群集,一个节点只能是群集的一部分。
确保在不同的环境中不要使用相同的群集名称,否则可能会导致连接错误的群集节点。例如,你可以使用
logging-dev、logging-stage、logging-prod分别为开发、阶段产品、生产集群做记录。
Node:
节点是单个服务器实例,它是群集的一部分,可以存储数据,并参与群集的索引和搜索功能。就像一个集
群,节点的名称默认为一个随机的通用唯一标识符(UUID),确定在启动时分配给该节点。如果不希望默认,
可以定义任何节点名。这个名字对管理很重要,目的是要确定你的网络服务器对应于ElasticSearch群集节点。
我们可以通过群集名配置节点以连接特定的群集。默认情况下,每个节点设置加入名为“elasticSearch”的
集群。这意味着如果你启动多个节点在网络上,假设他们能发现彼此,那么都会自动形成或加入一个名为
“elasticsearch”的集群。
shards&replicas:
shards:分片
索引可以存储大量的数据,这些数据可能超过单个节点的硬件限制。
为了解决这一问题,Elasticsearch提供将你的指标细分成多个块,即分片的能力。当你创建一个索引,你可
以简单地定义你想要的分片数量。每个分片本身是一个全功能的、独立的“指数”,可以托管在集群中的任何节点。
分片重要性:
|--分片允许水平拆分或缩放内容的大小
|--分片允许分配和并行操作碎片(可能在多个节点上)从而提高性能/吞吐量
这个机制中的碎片是分布式的,以及其文件汇总到搜索请求是完全由ElasticSearch管理,对用户来说是透明的。
replicas:复制
在同一个集群网络或云环境上,故障是任何时候都会出现的,拥有一个故障转移机制以防分片和结点因为某
些原因离线或消失是非常有用的,并且被强烈推荐。为此,Elasticsearch允许你创建一个或多个拷贝,并让你的
索引分片进入所谓的副本或称作复制品的分片,简称Replicas。
复制重要性:
|--副本为分片或节点提供了高可用性。为此,需要注意的是,一个副本的分片不会分配在同一个节点作为原始
或主分片,副本是从主分片那里复制过来的。
|--副本允许用户扩展你的搜索量或吞吐量,因为搜索可以在所有副本上并行执行。
## 映射创建,指定分词器:
创建流程:
1.获取ES服务的连接对象
2.准备文档构建对象
XContentFactory.jsonBuilder();
3.组装文档映射信息:格式参照json
4.获取mappings映射对象PutMappingRequest,创建索引库
Requests.putMappingRequest(Index).type(Type).source(构建对象);
5.将映射对象加入索引库
.admin().indices().putMapping(映射对象).get();
6.关闭资源
// 获取ES服务的了连接对象
TransportClient client = ESUtil.getClient();
// 构建文档信息
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject() //{
.startObject("article") // article:{
.startObject("properties") // properties:{
.startObject("id") // id:{
.field("type","integer") //设置类型 type:integer
.field("store","yes") //开启存储 store:yes
.endObject() // }
.startObject("title") // title:{
.field("type","string") //设置类型 type:string
.field("store","yes") //开启存储 store:yes
.field("analyzer","ik_smart") //设置分词器 analyzer:ik_smart
.endObject() // }
.startObject("content") // content:{
.field("type","string") //设置类型 type:string
.field("store","yes") //开启存储 store:yes
.field("analyzer","ik_smart") //设置分词器 analyzer:ik_smart
.endObject() // }
.endObject() // }
.endObject() // }
.endObject(); //}
// 获取mappings映射对象
PutMappingRequest mappingRequest =
Requests.putMappingRequest("blog").type("article").source(builder);
// 映射对象加入索引库
client.admin().indices().putMapping(mappingRequest).get();
// 关闭资源
client.close();
## 文档操作:
前置准备:导入依赖
jackson-core、jackson-databind、jackson-annotations、elasticSearch、transport
添加:利用jackson自动转换实体对象为文档信息
1.获取连接对象(工具类)
2.实例化文档实体对象,并设置相应属性
3.创建Jackson转换对象ObjectMapper,根据实体对象构建文档信息
.writeValueAsString(文档实体对象)
4.根据文档信息创建索引库
.prepareIndex(index, type, id).setSource(文档信息).get();
5.关闭资源
[注意]:
实体类层级类似于关系型数据库中表的层级,即应以索引库类型Type作为实体类名
// 获取ES服务的了连接对象
TransportClient client = ESUtil.getClient();
// 实例化实体类
Article article = new Article();
article.setId(1);
article.setTitle("title1");
article.setContent("content1");
// 创建Jackson转换对象,完成文档信息转换
ObjectMapper objectMapper = new ObjectMapper();
String document1 = objectMapper.writeValueAsString(article);
// 将文档信息加入指定的索引库
client.prepareIndex("blog1","article",article.getId().toString()).setSource(document1).get();
// 关闭资源
client.close();
修改:
1.获取连接对象(工具类)
2.实例化文档实体对象,并设置相应属性
3.创建Jackson转换对象并完成文档修改
覆盖添加方式:利用索引库Id不可重复特性
.prepareUpdate(index,type,id).setDoc(文档信息).get();
// 创建Jackson转换对象
ObjectMapper objectMapper = new ObjectMapper();
// 修改文档
client.prepareUpdate("blog1","article",article.getId().toString())
.setDoc(objectMapper.writeValueAsString(article)).get();
执行对象方式:
// 创建Jackson转换对象
ObjectMapper objectMapper = new ObjectMapper();
// 创建修改的执行对象
UpdateRequest updateRequest = new UpdateRequest("blog1","article",article.getId().toString());
updateRequest.doc(objectMapper.writeValueAsString(article));
// 修改文档
client.update(updateRequest).get();
4.关闭资源
删除:
1.获取连接对象
2.执行删除
prepareDelete方式:
client.prepareDelete("blog1","article","1").get();
执行对象方式:
// 创建Jackson转换对象
ObjectMapper objectMapper = new ObjectMapper();
// 创建删除的执行对象
DeleteRequest deleteRequest = new DeleteRequest("blog1","article","1");
// 修改文档
client.delete(deleteRequest).get();
3.关闭资源
查询所有:
基本流程:
1.获取连接对象
2.创建查询对象MatchAllQueryBuilder
.QueryBuilders.matchAllQuery()
3.构建查询请求对象SearchRequestBuilder
.prepareSearch(Index).setTypes(Type).setQuery(查询对象);
4.执行查询获取结果集对象SearchHits
.get().getHits();
5.处理结果
6.关闭资源
// 获取ES服务的连接对象
TransportClient client = ESUtil.getClient();
// 创建查询对象
MatchAllQueryBuilder query = QueryBuilders.matchAllQuery();
// 构建查询请求
SearchRequestBuilder requestBuilder = client.prepareSearch("blog1").setTypes("article").setQuery(query);
// 执行查询,获取响应结果
SearchResponse searchResponse = requestBuilder.get();
SearchHits hits = searchResponse.getHits();
// 处理结果
System.out.println("共命中:"+hits.getTotalHits()+" 条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()){
SearchHit searchHit = iterator.next();
System.out.println(searchHit.getSourceAsString());
}
// 关闭资源
client.close();
分页、排序:以基本流程为基础
3.构建查询请求,设置分页参数
SearchRequestBuilder.setFrom(...); //起始索引
SearchRequestBuilder.setSize(...); //每页条数
SearchRequestBuilder.addSort(field, order); //排序
[注意]:
原生ES查询不特意设置分页参数将默认显示1-10条数据
与SpringData整合后,将默认显示全部命中结果
// 构建查询请求
SearchRequestBuilder requestBuilder = client.prepareSearch("blog1").setTypes("article").setQuery(query);
// 设置分页参数
requestBuilder.setFrom(0);
requestBuilder.setSize(15);
// 设置排序
requestBuilder.addSort("id", SortOrder.ASC);
高亮:以基本流程为基础
3.构建查询请求,设置高亮
1.准备高亮对象HighlightBuilder
2.设置高亮词条
.field(...)
3.设置高亮前缀、后缀
.preTags("<font style = '...'>")
.postTags("</font>")
4.查询请求组装高亮对象
.highlightBuilder();
5.处理结果,获取高亮结果:
SearchHit.getHighlightFields().get(...).getFragments();
// 构建查询请求
SearchRequestBuilder requestBuilder = client.prepareSearch("blog2").setTypes("article").setQuery(query);
// 设置高亮
// 创建高亮对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<font style='red'>");
highlightBuilder.postTags("</font>");
// 将高亮对象加入到请求对象中
requestBuilder.highlighter(highlightBuilder);
// 执行查询,获取响应结果
SearchResponse searchResponse = requestBuilder.get();
// 处理结果
SearchHits hits = searchResponse.getHits();
System.out.println("一共命中"+hits.getTotalHits()+"条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()){
SearchHit searchHit = iterator.next();
// System.out.println(searchHit.getSourceAsString());
// System.out.println(searchHit.getHighlightFields().get("title").toString());
Text[] titles = searchHit.getHighlightFields().get("title").getFragments();
for (Text title : titles) {
System.out.println(title);
}
};