索引:相当于数据库,es可以把缩影放到一台服务器上,一个索引可以有一个或者多个分片,每个分片有多个副本。索引只是把一个或者多个分片组在一起的逻辑空间,文档存储在索引中。
索引类型:相当于数据库中的表,每个索引类型有不同的结构。
一个lucene实例,会xi
消耗相应的cpu,io,内存,文件描述
通常情况下很多场景在50GB大小以内,我们将平均大小控制在20GB到40GB之间
文档:每个文档,相当于数据库中一条记录,每个文档由多个字段构成,每个文档有不同的字段,并且有唯一标识符
映射:es默认创建索引和索引类型的mappi
一个文档不只有数据,还包含了元数据,相当于文档信息,三个必须的元数据节点
_index:文档存储的地方
_type:代表对象类
_id:文档唯一标识,id仅仅是一个字符串,他与_index和_type组合时,就是唯一标识文档,文档一个文档,可以定义一个id,也可以让elasticserach生成
分片大小:一般建议50G,太小多线程查询,多个并发,会降低查询吞吐量,非常大的分片,会使集权从故障中恢复能力产生负面影响
分片过多会导致检索时打开比较多的文件,也会导致多台服务器之前通讯,而分片数量过少,会导致分片过大,所以检索速度慢,一个索引会分成多个分分片数量在索引建立后不可更改。
性能调优:
1.关闭data节点的httpgong功能http.enabled: false。Head,bigdesk,marvel等监控插件,数据节点只需处理创建/更新/删除/查询索引数据操作
2.最小主节点防止脑裂
当集群异常,出现重选主节点,会出现多个主节点,称为脑裂。可she'设置最少ke'g可工作候选主节点个数,建议设置为(候选主节点/2)+1
discovery.zen.minimum_master_nodes
候选主节点设置为node.mater为true
3.指定集群及节点的名字
防止其他不小心加入集群
4.一台机器最好只部署一个node,但是一台服务器的cpu,内存,磁盘毕竟有限,不建议一个上面启动多个node
5.多个path.data,提高io性能
6.集群恢复配置
gateway.recover_after_nodes: 8。这个参数可以让es直到有足够的node都上线之后,再开始shard recovery的过程。
gateway.expected_nodes: 10,gateway.recover_after_time: 5m。经过上面的配置之后,es集群的行为会变成下面这样,等待至少8个节点在线,然后等待最多5分钟,或者10个节点都在线,开始shard recovery的过程
7.预留一般内存给luncene使用
8.es默认的堆内存是1.9G,不够用。建议分配物理机器的内存的一半,最大不超过32G
关闭linux的swap功能
9.分片数和备份数
创建索引的时候,最好指定相关的shards,配置total_shards_per_node参数,限制每个index每个节点最多分配多少个
副本数于索引的稳定性有比较大的关系,如果node挂了,会导致分片丢失,为保证数据的完整性,可以通过副本来解决这个问题,建议在建完索引后,执行optimize后。副本立马调整过来
10设置合理刷新时间
建立索引,不会立马查到,里面配置了index.refresh_interval参数,默认是1s。
这迫使集群每秒创建一个新的segment,可以设置30,60允许更大的的segment写入,减压以后,segment合并压力
这些内存里的segment就是可以被搜索shu数据,默认是1s生成一个segment,然后随着时间的流逝,内存里面的segment越来
越多。es还提供一个功能,叫做segment合并。
segment被检测满足合并策略,它会在内存里面被合并,随着时间的流逝,直到内存的segment达到了上限,这些数据会被刷新到磁盘上。
断电虽然segment中数据会没有,但是tranlog中记录数据,只有数据进入磁盘,tranlog数据才会被删除
11.根据业务设置合理的字段类型
文档值是存储在磁盘上的数据结构,在索引时,根据文档的原始值创建,文档值是一个列式存储风格的数据结构,非常适合执行存储喝聚合操作,除了字符类型分析字外,如果字段要对执行排序或者聚合操作,可以禁用文档值,节省磁盘空间。
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<!-- <version>7.9.2</version>-->
</dependency>
version版本要去掉,否则报错
Factory method 'elasticsearchRestHighLevelClient' threw exception; nested exception is java.lang.NoSuchFieldError: IGNORE_DEPRECATIONS
//批量插入
@GetMapping("/bulk")
public void bulk() throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
BulkRequest request=new BulkRequest();
request.add(new IndexRequest("peiyajie-2020","doc").
source(XContentType.JSON,"address","address1"));
request.add(new IndexRequest("peiyajie-2020","doc").
source(XContentType.JSON,"address","address2"));
request.add(new IndexRequest("peiyajie-2020","doc").
source(XContentType.JSON,"address","address3"));
request.add(new IndexRequest("peiyajie-2020","doc").
source(XContentType.JSON,"address","address4"));
//new DeleteRequest("peiyajie-2020","20")
// new UpdateRequest("peiyajie-2020","20").doc(XContentType.JSON,"other","foo3")
request.timeout(TimeValue.timeValueMinutes(2));
request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
request.waitForActiveShards(ActiveShardCount.ALL);
BulkResponse bulkResponse=client.bulk(request,RequestOptions.DEFAULT);
for(BulkItemResponse bulkItemResponse:bulkResponse) {
if(bulkItemResponse.isFailed()){
BulkItemResponse.Failure failure=bulkItemResponse.getFailure();
logger.info("failure.getMessage():"+failure.getMessage());
}
DocWriteResponse docWriteResponse=bulkItemResponse.getResponse();
switch (bulkItemResponse.getOpType()){
case INDEX:
case CREATE:
IndexResponse indexResponse=(IndexResponse)docWriteResponse;
logger.info("CREATE:");
break;
case UPDATE:
UpdateResponse updateResponse=(UpdateResponse)docWriteResponse;
logger.info("UPDATE:");
break;
case DELETE:
DeleteResponse deleteResponse=(DeleteResponse)docWriteResponse;
logger.info("DELETE:");
}
}
}
//高亮查询
@GetMapping("/highQuery")
public void highQuery(String address) throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
//定义索引库
SearchRequest searchRequest=new SearchRequest("peiyajie-2020");
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
//定义query查询
QueryBuilder queryBuilder = QueryBuilders.matchQuery("address", address);
//定义高亮查询
HighlightBuilder highlightBuilder=new HighlightBuilder();//高亮查询器
highlightBuilder.field("address");//高亮查询字段
highlightBuilder.requireFieldMatch(false);//如果要多个字段高亮,这项为false
highlightBuilder.preTags("<span style=\"color:red\">");//高亮设置
highlightBuilder.postTags("</span>");
//下面这两项,如果你要把高亮如文字内容等很多字段,必须配置,不然会导致高亮不全,文章内容缺失等
highlightBuilder.fragmentSize(800000);//最大高亮分片数
highlightBuilder.numOfFragments(0);//从第一个分片获取高亮片段
searchSourceBuilder.query(queryBuilder);
searchSourceBuilder.highlighter(highlightBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse=client.search(searchRequest,RequestOptions.DEFAULT);
List<Map<String,Object>> list=new ArrayList<Map<String,Object>>();
//遍历高亮结果
for(SearchHit hit:searchResponse.getHits().getHits()){
Map<String, HighlightField> highlightFields=hit.getHighlightFields();
HighlightField nameHighlight=highlightFields.get("address");
Map<String,Object> sourceAsMap=hit.getSourceAsMap();
if(nameHighlight!=null){
Text[] fragments=nameHighlight.getFragments();
String _address="";
for(Text text:fragments){
_address+=text;
}
sourceAsMap.put("address",_address);
list.add(sourceAsMap);
}
}
}
//删除
@GetMapping("/delete")
public void delete() throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
try {
DeleteRequest deleteRequest = new DeleteRequest("peiyajie-2020", "doc", "20");
//等待主分片可用的超时时间
deleteRequest.timeout(TimeValue.timeValueMinutes(10));
//一直保持请求连接中,直接当所做的更改对于搜索查询可见时的刷新发生后,再将结果返回
deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {//判断删除文档是否存在
logger.info("要删除的文档不存在");
return;
}
String index = deleteResponse.getIndex();
String type = deleteResponse.getType();
String id = deleteResponse.getId();
long version = deleteResponse.getVersion();
logger.info("index:" + index + ";type:" + type + ";id:" + id + ";version:" + version);
//查询分片执行的情况
ReplicationResponse.ShardInfo shardInfo = deleteResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
logger.info("未完全执行所有分片,总分片数为:" + shardInfo.getTotal() + ",执行的分片数:" + shardInfo.getSuccessful());
return;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
logger.info("失败原因:" + reason);
return;
}
}
}catch (ElasticsearchException e){
if(e.status()==RestStatus.CONFLICT){
logger.info("需要删除文档版本与现在文档冲突!");
}
}catch (Exception e){
e.printStackTrace();
}
}
//异步删除方法
//删除
@GetMapping("/deleteASyn")
public void deleteASyn() throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
DeleteRequest deleteRequest = new DeleteRequest("posts4", "doc", "1");
// DeleteRequest deleteRequest = new DeleteRequest("peiyajie-2020", "doc", "20").version(2);
// 注意:如果对一个文档添加版本条件(如id为2,版本为2)进行删除(删除后文档version变为3),再次删除时,
//等待主分片可用的超时时间
deleteRequest.timeout(TimeValue.timeValueMinutes(10));
//一直保持请求连接中,直接当所做的更改对于搜索查询可见时的刷新发生后,再将结果返回
deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
//异步回调对象
ActionListener<DeleteResponse> listener = new ActionListener<DeleteResponse>() {
@Override
public void onResponse(DeleteResponse deleteResponse) {
if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) {
logger.info("未找到需要删除的文档!");
return;
}
String index = deleteResponse.getIndex();
String type = deleteResponse.getType();
String id = deleteResponse.getId();
long version = deleteResponse.getVersion();
logger.info("index:" + index + ";type:" + type + ";id:" + id + ";version:" + version);
//查询分片执行的情况
ReplicationResponse.ShardInfo shardInfo = deleteResponse.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
logger.info("未完全执行所有分片,总分片数为:" + shardInfo.getTotal() + ",执行的分片数:" + shardInfo.getSuccessful());
return;
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
logger.info("失败原因:" + reason);
return;
}
}
}
@Override
public void onFailure(Exception e) {
}
};
client.deleteAsync(deleteRequest, RequestOptions.DEFAULT,listener);
//所有异步操作,一定不要将client关闭太早,否则操作还没执行程序就被中止了
//所以同步方法创作对象可以放在try中,执行完自动关闭,而异步方法不可以
}
//同步新增方法
@GetMapping("/index")
public void index() throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
XContentBuilder builder=XContentFactory.jsonBuilder();
builder.startObject();
{
builder.field("user","kimchy");
builder.timeField("postDate",new Date());
builder.field("message","trying out Elasticsearch");
}
builder.endObject();
IndexRequest indexRequest=new IndexRequest("peiyajie-2020","doc","20").source(builder);
indexRequest.timeout(TimeValue.timeValueSeconds(5));
//DocWriteRequest.OpType.INDEX如果文档存在,则更新文档。文档不存在,则创建文档
//DocWriteRequest.OpType.CREATE。如果文档存在,则报错,根据id来判断
indexRequest.opType(DocWriteRequest.OpType.INDEX);
try{
IndexResponse indexResponse=client.index(indexRequest,RequestOptions.DEFAULT);
String index=indexResponse.getIndex();
String type=indexResponse.getType();
String id=indexResponse.getId();
long version=indexResponse.getVersion();
if(indexResponse.getResult()== DocWriteResponse.Result.CREATED){
//处理(如果需要)第一次创建文档的情况
logger.info("添加成功");
logger.info("index:"+index);
logger.info("type:"+type);
logger.info("id:"+id);
logger.info("version:"+version);
logger.info("key-pairs形式的注入处理(如果需要)第一次创建文档的情况");
}else if (indexResponse.getResult()== DocWriteResponse.Result.UPDATED){
//处理(如果需要)文档被重写的情况
logger.info("更新成功");
logger.info("index:"+index);
logger.info("type:"+type);
logger.info("id:"+id);
logger.info("version:"+version);
logger.info("key-pairs形式的注入处理(如果需要)文档被重写的情况");
}
}catch(ElasticsearchException e){
if(e.status()==RestStatus.CONFLICT){
logger.info("创建的文档与已存在的发生冲突");
}
}
client.close();
}
//异步新增
@GetMapping("/indexAsync")
public void indexAsync() throws IOException {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(
new HttpHost("p43148v.hulk.shbt.qihoo.net",9200,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9201,"http"),
new HttpHost("p43148v.hulk.shbt.qihoo.net",9202,"http")));
XContentBuilder builder=XContentFactory.jsonBuilder();
builder.startObject();
{
builder.field("user","kimchy");
builder.timeField("postDate",new Date());
builder.field("message","trying out Elasticsearchpeiyajie");
}
builder.endObject();
//id为null的话,会创建一个自动生成的id
IndexRequest indexRequest=new IndexRequest("posts4","doc","20").source(builder);
indexRequest.timeout(TimeValue.timeValueSeconds(5));
//DocWriteRequest.OpType.INDEX如果文档存在,则更新文档。文档不存在,则创建文档
//DocWriteRequest.OpType.CREATE。如果文档存在,则报错,根据id来判断
indexRequest.opType(DocWriteRequest.OpType.INDEX);
ActionListener<IndexResponse> listener=new ActionListener<IndexResponse>(){
@Override
public void onResponse(IndexResponse indexResponse) {
String index=indexResponse.getIndex();
String type=indexResponse.getType();
String id=indexResponse.getId();
long version=indexResponse.getVersion();
if(indexResponse.getResult()== DocWriteResponse.Result.CREATED){
//处理(如果需要)第一次创建文档的情况
logger.info("添加成功");
logger.info("index:"+index);
logger.info("type:"+type);
logger.info("id:"+id);
logger.info("version:"+version);
logger.info("key-pairs形式的注入处理(如果需要)第一次创建文档的情况");
}else if (indexResponse.getResult()== DocWriteResponse.Result.UPDATED){
//处理(如果需要)文档被重写的情况
logger.info("更新成功");
logger.info("index:"+index);
logger.info("type:"+type);
logger.info("id:"+id);
logger.info("version:"+version);
logger.info("key-pairs形式的注入处理(如果需要)文档被重写的情况");
}
}
@Override
public void onFailure(Exception e) {
ElasticsearchException elasticsearchException=(ElasticsearchException) e;
if(elasticsearchException.status()==RestStatus.CONFLICT){
logger.info("创建文档已存在");
}
}
};
client.indexAsync(indexRequest,RequestOptions.DEFAULT,listener);
// client.close();如果不被注释掉,可能还没有将请求发送出去,连接就会被关闭,从而创建或者更新失败
}