一、认识阿里云检索分析服务Elasticsearch版
阿里云检索分析服务Elasticsearch版是一款基于开源Elasticsearch构建的全托管式云服务,兼容ELK技术栈,提供免运维、弹性伸缩的搜索与分析能力。它广泛应用于数据库加速、信息检索、日志分析、智能运维监控等场景。相较于自建Elasticsearch集群,阿里云ES提供了云原生高性能内核、达摩院NLP分词、向量检索、智能运维以及免费的X-Pack高级商业特性等能力。
需要先登录阿里云控制台,点击:阿里云控制台
二、创建与初始化Elasticsearch实例
2.1 创建实例的核心参数
登录阿里云控制台后,进入Elasticsearch产品页面,点击创建实例。关键配置建议如下:
- 付费类型:测试阶段选择按量付费,生产环境建议转为包年包月以降低成本。
- 地域与可用区:选择与业务应用服务器相同的VPC和可用区,确保内网互通。
- 实例版本:推荐通用商业版8.x或7.x版本。中文搜索场景需预先安装IK分词插件——阿里云ES默认已集成该插件。
- 数据节点规格:建议从2核8GB起步,存储类型选择SSD云盘以获得更好的索引写入性能。
- 数据节点数量:至少2个节点以保证高可用。
配置完成后等待约20分钟,实例状态变为"正常"即可使用。
2.2 网络白名单配置
为确保客户端能够访问Elasticsearch实例,必须正确配置白名单。如果运行代码的服务器在公网环境,需开启实例的公网地址,并将服务器的公网IP加入白名单。如果服务器与ES实例在同一VPC内,可通过私网地址连通,需确保VPC私网访问白名单已添加服务器的内网IP。
安全提示:切勿将白名单设置为0.0.0.0/0,这会使实例完全暴露在公网中,带来严重安全风险。
2.3 配置Kibana访问
Kibana已内置于阿里云ES控制台,无需单独安装。在实例详情页找到Kibana公网访问地址,默认白名单禁止所有IP访问,需将本地开发机或办公网络的公网IP添加到白名单中。登录鉴权采用双重验证:先登录阿里云账号,然后使用elastic用户名和实例创建时设置的密码进行二次验证。
三、索引设计与映射配置
3.1 索引的三种创建方式
Elasticsearch索引的创建主要有三种方式:
- 默认创建:直接执行PUT /my_index,ES使用默认配置并启用动态映射自动识别字段类型。适用于测试和快速原型开发。
- 自定义配置创建:在请求体中明确指定settings(分片、副本)和mappings(字段类型、分析器)。适用于生产环境,需要对性能和数据类型精细控制。
- 使用模板创建:预先定义index_patterns(如logs-*),当创建匹配模式的索引时模板配置自动应用。适用于日志等需要自动管理大量索引的场景。
3.2 Mapping核心设计原则
索引映射相当于数据库的表结构设计,决定了每个字段如何被存储和搜索。最核心的字段类型区分为text和keyword两种:
- text类型:用于可分词的全文搜索场景,如文章标题、商品描述等。该类型字段会被分词器处理,生成倒排索引。
- keyword类型:用于精确匹配场景,如标签、状态码、ID等。该类型字段不会被分词,保留原始值用于term查询。
以下是一个完整的索引创建示例,包含了settings和mappings的配置:
PUT /product_info { "settings": { "number_of_shards": 3, "number_of_replicas": 2 }, "mappings": { "properties": { "product_id": { "type": "keyword" }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "price": { "type": "double" }, "in_stock": { "type": "boolean" }, "created_date": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||epoch_millis" } } } }
3.3 分片与副本的选型策略
分片大小建议为10GB到50GB之间。分片太多会产生管理开销,分片太大会导致故障恢复慢。分片数应大于等于节点数,才能充分利用所有节点的计算资源。副本是主分片的完整拷贝,用于高可用和扩展查询吞吐,但每个副本都会消耗和主分片一样多的磁盘。生产环境至少为1个副本,通常1或2即可。
3.4 IK中文分词器配置
阿里云ES Serverless内置IK分词、同义词、关键词过滤等插件,支持用户上传自定义词库。IK分词器支持两种分词模式:
- ik_max_word:将文本按照最细粒度拆分,适合术语查询。例如"计算机汉字输入方法"拆分为"计算机"、"计算"、"算机"、"汉字输入"、"汉字"、"输入"、"方法"。
- ik_smart:将文本按照粗粒度拆分,适合短语查询。例如"计算机汉字输入方法"拆分为"计算机"、"汉字输入"、"方法"。
在索引映射中指定使用IK分词器:
PUT /article_index { "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" } } } }
四、多语言客户端接入
4.1 Java High Level REST Client
官方推荐使用High Level REST Client,它通过HTTP与Elasticsearch通信,避免了Transport Client的版本兼容性问题。High Level Client能够向上兼容,例如6.7.0版本的客户端能确保与大于等于6.7.0版本的Elasticsearch集群通信。
Maven依赖配置:
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.17.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency>
客户端连接与索引创建示例:
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentType; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; public class ESClientExample { public static void main(String[] args) throws Exception { // 配置认证信息 CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials( AuthScope.ANY, new UsernamePasswordCredentials("elastic", "your_password") ); // 创建客户端 - 使用公网地址 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("es-cn-xxxx.elasticsearch.aliyuncs.com", 9200, "https") ).setHttpClientConfigCallback( httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) ) ); // 创建索引 CreateIndexRequest request = new CreateIndexRequest("my_index"); request.settings(Settings.builder() .put("index.number_of_shards", 3) .put("index.number_of_replicas", 2) ); request.mapping( "{\n" + " \"properties\": {\n" + " \"title\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" },\n" + " \"content\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" },\n" + " \"tags\": { \"type\": \"keyword\" },\n" + " \"create_time\": { \"type\": \"date\" }\n" + " }\n" + "}", XContentType.JSON ); CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); System.out.println("索引创建成功: " + response.isAcknowledged()); client.close(); } }
4.2 Python客户端
Python开发者可以使用官方elasticsearch库:
from elasticsearch import Elasticsearch from elasticsearch import helpers # 连接阿里云ES实例 es = Elasticsearch( ["https://es-cn-xxxx.elasticsearch.aliyuncs.com:9200"], http_auth=("elastic", "your_password"), verify_certs=False ) # 创建索引 index_body = { "settings": { "number_of_shards": 3, "number_of_replicas": 2 }, "mappings": { "properties": { "title": {"type": "text", "analyzer": "ik_max_word"}, "content": {"type": "text", "analyzer": "ik_max_word"}, "tags": {"type": "keyword"}, "create_time": {"type": "date"} } } } if not es.indices.exists(index="my_index"): es.indices.create(index="my_index", body=index_body) print("索引创建成功") # 批量写入数据 actions = [ { "_index": "my_index", "_source": { "title": "阿里云Elasticsearch使用指南", "content": "本文详细介绍阿里云ES的对接使用方法...", "tags": ["阿里云", "Elasticsearch", "搜索"], "create_time": "2026-07-04T10:00:00" } }, { "_index": "my_index", "_source": { "title": "Elasticsearch全文搜索最佳实践", "content": "深入探讨ES全文搜索的优化技巧...", "tags": ["Elasticsearch", "全文搜索", "优化"], "create_time": "2026-07-04T11:00:00" } } ] helpers.bulk(es, actions) print("数据批量写入完成") # 执行搜索 result = es.search( index="my_index", body={ "query": { "match": { "title": "阿里云" } } } ) print(f"搜索结果: {result['hits']['total']['value']} 条") for hit in result['hits']['hits']: print(f"- {hit['_source']['title']}")
4.3 Go客户端
Go语言可使用官方Elasticsearch Go Client:
package main import ( "bytes" "context" "encoding/json" "fmt" "log" "github.com/elastic/go-elasticsearch/v8" "github.com/elastic/go-elasticsearch/v8/esapi" ) func main() { // 配置客户端 cfg := elasticsearch.Config{ Addresses: []string{ "https://es-cn-xxxx.elasticsearch.aliyuncs.com:9200", }, Username: "elastic", Password: "your_password", } es, err := elasticsearch.NewClient(cfg) if err != nil { log.Fatalf("创建客户端失败: %s", err) } // 创建索引 mapping := `{ "settings": { "number_of_shards": 3, "number_of_replicas": 2 }, "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_max_word" }, "content": { "type": "text", "analyzer": "ik_max_word" }, "tags": { "type": "keyword" }, "create_time": { "type": "date" } } } }` req := esapi.IndicesCreateRequest{ Index: "my_index", Body: bytes.NewReader([]byte(mapping)), } res, err := req.Do(context.Background(), es) if err != nil { log.Fatalf("创建索引失败: %s", err) } defer res.Body.Close() fmt.Println("索引创建成功") // 索引文档 doc := map[string]interface{}{ "title": "阿里云Elasticsearch使用指南", "content": "本文详细介绍阿里云ES的对接使用方法...", "tags": []string{"阿里云", "Elasticsearch"}, "create_time": "2026-07-04T10:00:00", } docJSON, _ := json.Marshal(doc) indexReq := esapi.IndexRequest{ Index: "my_index", DocumentID: "1", Body: bytes.NewReader(docJSON), Refresh: "true", } indexRes, err := indexReq.Do(context.Background(), es) if err != nil { log.Fatalf("索引文档失败: %s", err) } defer indexRes.Body.Close() fmt.Println("文档索引成功") }
五、数据写入与实时同步
5.1 单条与批量写入
除了上述各语言客户端的写入方式外,还可以直接通过RESTful API进行操作。批量写入使用_bulk API可显著提升吞吐量:
POST /my_index/_bulk {"index": {"_id": "1"}} {"title": "文档1", "content": "内容1", "tags": ["标签1"], "create_time": "2026-07-04T10:00:00"} {"index": {"_id": "2"}} {"title": "文档2", "content": "内容2", "tags": ["标签2"], "create_time": "2026-07-04T11:00:00"} {"index": {"_id": "3"}} {"title": "文档3", "content": "内容3", "tags": ["标签3"], "create_time": "2026-07-04T12:00:00"}
5.2 通过实时计算Flink同步数据
阿里云实时计算Flink提供了非常简单的方式来对接Elasticsearch,可帮助快速创建实时搜索链路。对于更复杂的写入需求,可以使用Flink的自定义Sink功能来实现。
六、查询与检索分析
6.1 DSL查询语法
Elasticsearch提供了强大的DSL(Domain Specific Language)查询语法。以下是一个多条件组合查询示例:
GET /my_index/_search { "query": { "bool": { "must": [ { "match": { "title": "阿里云" } }, { "term": { "tags": "Elasticsearch" } } ], "filter": [ { "range": { "create_time": { "gte": "2026-07-01", "lte": "2026-07-31" } } } ], "should": [ { "match": { "content": "指南" } } ], "minimum_should_match": 1 } }, "sort": [ { "create_time": { "order": "desc" } } ], "highlight": { "fields": { "title": {}, "content": {} } }, "from": 0, "size": 20 }
6.2 查询加速插件analytic-search
analytic-search是阿里云Elasticsearch团队自主开发的日志场景检索插件,提供Kibana Discover查询加速和查询并发两项功能。该插件为系统默认插件,默认已安装且不可卸载。
Kibana Discover查询加速:通过优化索引合并策略及Date_histogram执行计划策略,在没有查询条件或仅有一个查询条件时大幅降低查询耗时。在索引settings中配置index.sort按时间戳字段降序排列即可开启:
PUT test_log { "settings": { "index.points.same_sort_order_as_index_sort": true, "index.sort.field": ["@timestamp"], "index.sort.order": ["desc"] }, "mappings": { "properties": { "@timestamp": { "type": "date" } } } }
查询并发功能:通过实现召回过程的并发,提高资源利用率,召回阶段平均耗时降低50%。开启方式如下:
PUT _cluster/settings { "persistent": { "apack.analytic_search.doc_concurrency.enabled": "true" } }
6.3 向量检索插件aliyun-knn
阿里云Elasticsearch向量检索功能基于插件扩展机制实现,完全兼容原生Elasticsearch版本。向量索引支持实时增量写入。使用前需确保数据节点规格为16核64GB及以上。该插件可用于图像搜索、视频指纹采样、人脸识别、语音识别和商品推荐等场景。
创建向量索引的示例:
PUT /vector_index { "mappings": { "properties": { "image_vector": { "type": "dense_vector", "dims": 128, "index": true, "similarity": "cosine" }, "title": { "type": "text", "analyzer": "ik_max_word" } } } }
6.4 Kibana数据可视化
Kibana是Elasticsearch的数据可视化和探索工具,可以通过它对ES中的数据进行查询、分析和可视化。Kibana的Visualize功能支持基于ES查询聚合创建可视化图表,用于呈现索引数据的分布和趋势。
七、索引生命周期管理与冷热分离
Elasticsearch 6.6.0及以上版本提供了索引生命周期管理(ILM)功能,将索引生命周期分为hot、warm、cold、delete四个阶段:
- hot阶段:处理时序数据的实时写入,可根据文档数、大小、时长决定是否滚动更新索引。
- warm阶段:索引不再写入,主要提供查询。
- cold阶段:索引不再更新,查询频率低。
- delete阶段:索引将被删除。
冷热集群包含冷、热两种属性的节点。热节点处理实时写入,建议使用SSD云盘和高规格配置;冷节点存储历史数据,建议使用高效云盘或OpenStore实现海量冷数据Serverless存储。
以下是一个ILM策略配置示例:
PUT _ilm/policy/my_policy { "policy": { "phases": { "hot": { "actions": { "rollover": { "max_size": "50GB", "max_age": "30d" } } }, "warm": { "min_age": "30d", "actions": { "shrink": { "number_of_shards": 1 }, "forcemerge": { "max_num_segments": 1 } } }, "cold": { "min_age": "60d", "actions": { "migrate": { "enabled": true } } }, "delete": { "min_age": "90d", "actions": { "delete": {} } } } } }
八、安全管控与权限体系
8.1 X-Pack RBAC角色权限管控
Elasticsearch X-Pack提供了RBAC(Role-based Access Control)机制,可以为自定义角色分配权限,并将角色分配给用户,实现精细化的权限管控。Elasticsearch提供了多种内置角色,也可以创建自定义角色以满足特定需求。
创建角色的关键参数:
- Cluster privileges:定义集群的操作权限,如查看集群健康度、创建快照等。
- Index privileges:定义索引的操作权限,索引名支持通配符(*)及正则表达式。
- Kibana privileges:定义Kibana操作权限。
角色创建完成后,创建用户并为该用户分配对应角色,即可授予该角色拥有的权限。
8.2 RAM子账号授权
使用RAM可以避免与其他用户共享阿里云账号密钥,并可按需为用户授予最小权限。使用RAM管理员登录RAM控制台,在用户页面单击目标RAM用户操作列的添加权限。完成授权后,可以RAM用户身份登录阿里云Elasticsearch控制台,权限立即生效。
九、监控运维与最佳实践
9.1 可观测数据接入云监控
阿里云检索分析服务Elasticsearch版的可观测数据可以接入到云监控2.0。选择目标工作空间后,在导航栏中单击接入中心,找到检索分析服务Elasticsearch版接入卡片。接入后可在实体查询应用或云产品洞察相关应用中查看接入的实体及相关可观测数据。
9.2 最佳实践总结
- 索引设计:合理规划分片数(建议10-50GB/分片),生产环境至少配置1个副本。
- 中文搜索:使用IK分词插件,根据场景选择ik_max_word或ik_smart。
- 冷热分离:对时序数据启用ILM策略,将历史数据自动迁移到冷节点以降低成本。
- 查询优化:日志场景开启analytic-search查询加速插件;向量检索场景启用aliyun-knn插件。
- 安全管控:使用X-Pack RBAC实现细粒度权限控制,配合RAM子账号进行云资源授权。
- 网络配置:生产环境优先使用VPC内网访问,避免公网暴露。
十、常见问题解答
问1:Java High Level REST Client与Elasticsearch集群版本必须一致吗?
High Level Client能够向上兼容,例如6.7.0版本的客户端能确保与大于等于6.7.0版本的Elasticsearch集群通信。但为了保证最大程度地使用新版客户端的特性,推荐客户端版本与集群版本一致。
问2:如何解决连接Elasticsearch时提示Timeout connecting的问题?
通常是因为白名单未正确配置。检查是否将运行代码的服务器的公网IP(公网访问场景)或内网IP(VPC内网访问场景)添加到了实例的白名单中。
问3:IK分词器的ik_max_word和ik_smart有什么区别?
ik_max_word将文本按照最细粒度拆分,适合术语查询;ik_smart将文本按照粗粒度拆分,适合短语查询。通常建议索引时使用ik_max_word以获得更全的分词结果,搜索时使用ik_smart以提高查询精准度。
问4:索引生命周期管理(ILM)的四个阶段分别是什么?
ILM将索引生命周期分为hot(热数据实时写入)、warm(温数据只读查询)、cold(冷数据低频访问)、delete(删除)四个阶段。
问5:阿里云ES的向量检索功能有什么使用要求?
使用向量检索插件aliyun-knn前,需要确保阿里云Elasticsearch实例的数据节点规格为16核64GB及以上。向量索引支持实时增量写入,完全兼容原生Elasticsearch版本。
问6:如何实现Elasticsearch的细粒度权限控制?
通过Elasticsearch X-Pack的RBAC机制,可以创建自定义角色并分配集群权限、索引权限和Kibana权限,然后将角色分配给用户。配合阿里云RAM子账号体系,可以实现云资源层面的最小权限授权。