Elasticsearch最佳实践
2025/8/15大约 3 分钟
Elasticsearch最佳实践
前置知识
在学习本文之前,请确保您已经:
- 掌握Elasticsearch的基本使用
- 了解Elasticsearch的高级特性
- 有实际的项目开发经验
索引设计最佳实践
1. 合理设计Mapping
PUT my_index
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"description": {
"type": "text",
"analyzer": "ik_max_word"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
},
"createTime": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
2. 索引模板
@Service
@RequiredArgsConstructor
public class IndexTemplateService {
private final RestHighLevelClient client;
public void createTemplate() throws IOException {
PutIndexTemplateRequest request = new PutIndexTemplateRequest("my_template");
request.patterns(Arrays.asList("product-*"));
request.order(0);
Map<String, Object> mappings = new HashMap<>();
// ... 设置mappings
Map<String, Object> settings = new HashMap<>();
// ... 设置settings
request.mapping(mappings);
request.settings(settings);
client.indices().putTemplate(request, RequestOptions.DEFAULT);
}
}
性能优化最佳实践
1. 批量操作
public class BulkOperationService {
private final ElasticsearchOperations elasticsearchOperations;
private final int BATCH_SIZE = 1000;
public void bulkIndex(List<Product> products) {
List<IndexQuery> queries = new ArrayList<>();
for (Product product : products) {
IndexQuery indexQuery = new IndexQueryBuilder()
.withId(product.getId())
.withObject(product)
.build();
queries.add(indexQuery);
// 达到批量大小时执行
if (queries.size() == BATCH_SIZE) {
elasticsearchOperations.bulkIndex(queries, Product.class);
queries.clear();
}
}
// 处理剩余的文档
if (!queries.isEmpty()) {
elasticsearchOperations.bulkIndex(queries, Product.class);
}
}
}
2. 查询优化
public SearchHits<Product> optimizedSearch(
String keyword, String category, Double minPrice, Double maxPrice) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 关键词搜索
if (StringUtils.hasText(keyword)) {
boolQuery.must(QueryBuilders.multiMatchQuery(keyword)
.field("title", 3.0f)
.field("description")
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS));
}
// 过滤条件
if (StringUtils.hasText(category)) {
boolQuery.filter(QueryBuilders.termQuery("category", category));
}
if (minPrice != null || maxPrice != null) {
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
if (minPrice != null) rangeQuery.gte(minPrice);
if (maxPrice != null) rangeQuery.lte(maxPrice);
boolQuery.filter(rangeQuery);
}
// 使用PageRequest替代Scroll
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withPageable(PageRequest.of(0, 20))
.withSort(SortBuilders.fieldSort("_score").order(SortOrder.DESC))
.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.build();
return elasticsearchOperations.search(searchQuery, Product.class);
}
监控与运维最佳实践
1. 健康检查
@Service
@RequiredArgsConstructor
public class HealthCheckService {
private final RestHighLevelClient client;
public boolean isClusterHealthy() {
try {
ClusterHealthResponse response = client.cluster().health(
new ClusterHealthRequest(),
RequestOptions.DEFAULT
);
return response.getStatus() != ClusterHealthStatus.RED;
} catch (IOException e) {
return false;
}
}
public Map<String, Object> getClusterStats() {
try {
ClusterStatsResponse response = client.cluster().stats(
new ClusterStatsRequest(),
RequestOptions.DEFAULT
);
Map<String, Object> stats = new HashMap<>();
stats.put("nodes", response.getNodesStats());
stats.put("indices", response.getIndicesStats());
return stats;
} catch (IOException e) {
return Collections.emptyMap();
}
}
}
2. 数据备份
@Service
@RequiredArgsConstructor
public class BackupService {
private final RestHighLevelClient client;
public CreateSnapshotResponse createSnapshot(
String repositoryName,
String snapshotName
) throws IOException {
CreateSnapshotRequest request = new CreateSnapshotRequest()
.repository(repositoryName)
.snapshot(snapshotName)
.waitForCompletion(true);
return client.snapshot().create(request, RequestOptions.DEFAULT);
}
public RestoreSnapshotResponse restoreSnapshot(
String repositoryName,
String snapshotName
) throws IOException {
RestoreSnapshotRequest request = new RestoreSnapshotRequest()
.repository(repositoryName)
.snapshot(snapshotName)
.waitForCompletion(true);
return client.snapshot().restore(request, RequestOptions.DEFAULT);
}
}
安全配置最佳实践
1. 身份认证
# elasticsearch.yml
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
@Configuration
public class ElasticsearchConfig {
@Bean
public RestHighLevelClient elasticsearchClient() {
final CredentialsProvider credentialsProvider =
new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("elastic", "password"));
RestClientBuilder builder = RestClient.builder(
new HttpHost("localhost", 9200, "https"))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider)
.setSSLContext(createSSLContext()));
return new RestHighLevelClient(builder);
}
private SSLContext createSSLContext() {
// ... SSL配置代码
return null;
}
}
2. 角色权限
# 创建角色
POST /_security/role/read_only
{
"cluster": ["monitor"],
"indices": [
{
"names": ["product-*"],
"privileges": ["read", "view_index_metadata"]
}
]
}
总结
本文介绍了Elasticsearch的以下最佳实践:
- ✅ 索引设计优化
- ✅ 性能调优方案
- ✅ 监控与运维
- ✅ 安全配置
建议
- 根据实际业务场景选择合适的实践方案
- 定期进行性能测试和优化
- 建立完善的监控和告警机制
希望这篇文章对您有所帮助!如果您有任何问题,欢迎在评论区讨论。