Amazon OpenSearch Service
最后更新: June 30, 2026
Amazon OpenSearch Service 是一项完全托管的搜索和分析服务,用于实时应用程序监控、日志分析和网站搜索。它基于 OpenSearch(Elasticsearch 的一个分支),并提供强大的全文搜索功能。
目录
概述
OpenSearch 与 Elasticsearch
OpenSearch 是 AWS 于 2021 年从 Elasticsearch 7.10 分支创建的开源项目。
| 特性 | OpenSearch | Elasticsearch |
|---|---|---|
| 许可证 | Apache 2.0 | SSPL/Elastic License |
| 托管服务 | Amazon OpenSearch Service | Elastic Cloud |
| 兼容性 | 与 ES 7.10 API 兼容 | 最新版本 |
| 插件 | OpenSearch 插件 | Elastic 插件 |
| Dashboard | OpenSearch Dashboards | Kibana |
Amazon OpenSearch Service 功能
+-------------------------------------------------------------+
| Amazon OpenSearch Service |
+-------------------------------------------------------------+
| Fully managed | Multi-AZ deployment | Auto snapshots |
| Auto patching | Encryption (rest/transit) | VPC integration |
| Fine-grained Access | SAML authentication | CloudWatch |
| UltraWarm/Cold storage | Serverless option | Cross-cluster |
+-------------------------------------------------------------+主要使用场景
- 日志分析:应用程序、基础设施和安全日志分析
- 全文搜索:网站、文档和产品搜索
- 安全分析:SIEM、威胁检测、合规性
- 实时监控:应用程序性能监控
- 业务分析:点击流、用户行为分析
架构
OpenSearch 集群架构
节点类型
参考:有关 AWS 实例类型性能基准,请参阅 AWS Instance Benchmark。
| 节点类型 | 角色 | 推荐实例 |
|---|---|---|
| Master | 集群管理、索引元数据 | m6g.large.search (3) |
| Data | 数据存储、搜索/索引 | r6g.xlarge.search |
| UltraWarm | 只读、经济高效的存储 | ultrawarm1.medium |
| Cold | 基于 S3 的归档 | - |
数据流
创建 Domain
通过 AWS Console 创建
1. Access OpenSearch Service console
2. Click "Create domain"
3. Settings:
- Deployment type: Production
- Version: OpenSearch 2.x
- Data nodes: r6g.xlarge.search x 3
- Master nodes: m6g.large.search x 3
- EBS: gp3, 500GB per node
- Network: VPC access
- Encryption: Enable at-rest and in-transit encryption
- Enable Fine-grained access control通过 Terraform 创建
hcl
# opensearch.tf
# VPC and subnet data
data "aws_vpc" "main" {
tags = {
Name = "main-vpc"
}
}
data "aws_subnets" "private" {
filter {
name = "vpc-id"
values = [data.aws_vpc.main.id]
}
filter {
name = "tag:Type"
values = ["private"]
}
}
# Security group
resource "aws_security_group" "opensearch" {
name = "opensearch-sg"
description = "Security group for OpenSearch domain"
vpc_id = data.aws_vpc.main.id
ingress {
description = "HTTPS from VPC"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [data.aws_vpc.main.cidr_block]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "opensearch-sg"
}
}
# OpenSearch domain
resource "aws_opensearch_domain" "main" {
domain_name = "logs-production"
engine_version = "OpenSearch_2.11"
cluster_config {
instance_type = "r6g.xlarge.search"
instance_count = 3
zone_awareness_enabled = true
dedicated_master_enabled = true
dedicated_master_type = "m6g.large.search"
dedicated_master_count = 3
zone_awareness_config {
availability_zone_count = 3
}
# UltraWarm settings
warm_enabled = true
warm_type = "ultrawarm1.medium.search"
warm_count = 2
# Cold Storage settings
cold_storage_options {
enabled = true
}
}
# EBS settings
ebs_options {
ebs_enabled = true
volume_type = "gp3"
volume_size = 500
iops = 3000
throughput = 250
}
# VPC settings
vpc_options {
subnet_ids = slice(data.aws_subnets.private.ids, 0, 3)
security_group_ids = [aws_security_group.opensearch.id]
}
# Encryption settings
encrypt_at_rest {
enabled = true
}
node_to_node_encryption {
enabled = true
}
domain_endpoint_options {
enforce_https = true
tls_security_policy = "Policy-Min-TLS-1-2-2019-07"
}
# Fine-grained Access Control
advanced_security_options {
enabled = true
internal_user_database_enabled = true
master_user_options {
master_user_name = "admin"
master_user_password = var.opensearch_master_password
}
}
# Advanced settings
advanced_options = {
"rest.action.multi.allow_explicit_index" = "true"
"indices.fielddata.cache.size" = "20"
"indices.query.bool.max_clause_count" = "1024"
}
# Auto snapshots
snapshot_options {
automated_snapshot_start_hour = 23
}
# Logging
log_publishing_options {
cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_index_slow.arn
log_type = "INDEX_SLOW_LOGS"
enabled = true
}
log_publishing_options {
cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_search_slow.arn
log_type = "SEARCH_SLOW_LOGS"
enabled = true
}
log_publishing_options {
cloudwatch_log_group_arn = aws_cloudwatch_log_group.opensearch_error.arn
log_type = "ES_APPLICATION_LOGS"
enabled = true
}
tags = {
Environment = "production"
Application = "logging"
}
depends_on = [aws_iam_service_linked_role.opensearch]
}
# CloudWatch log groups
resource "aws_cloudwatch_log_group" "opensearch_index_slow" {
name = "/aws/opensearch/logs-production/index-slow-logs"
retention_in_days = 30
}
resource "aws_cloudwatch_log_group" "opensearch_search_slow" {
name = "/aws/opensearch/logs-production/search-slow-logs"
retention_in_days = 30
}
resource "aws_cloudwatch_log_group" "opensearch_error" {
name = "/aws/opensearch/logs-production/error-logs"
retention_in_days = 30
}
# Service-linked role
resource "aws_iam_service_linked_role" "opensearch" {
aws_service_name = "opensearchservice.amazonaws.com"
}
# CloudWatch log resource policy
resource "aws_cloudwatch_log_resource_policy" "opensearch" {
policy_name = "opensearch-log-policy"
policy_document = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "es.amazonaws.com"
}
Action = [
"logs:PutLogEvents",
"logs:CreateLogStream"
]
Resource = [
"${aws_cloudwatch_log_group.opensearch_index_slow.arn}:*",
"${aws_cloudwatch_log_group.opensearch_search_slow.arn}:*",
"${aws_cloudwatch_log_group.opensearch_error.arn}:*"
]
}
]
})
}
# Outputs
output "opensearch_endpoint" {
value = aws_opensearch_domain.main.endpoint
}
output "opensearch_dashboard_endpoint" {
value = aws_opensearch_domain.main.dashboard_endpoint
}索引管理
索引模板
json
PUT _index_template/logs-template
{
"index_patterns": ["logs-*"],
"priority": 100,
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s",
"index.codec": "best_compression",
"index.mapping.total_fields.limit": 2000,
"index.translog.durability": "async",
"index.translog.sync_interval": "30s"
},
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"level": {
"type": "keyword"
},
"message": {
"type": "text",
"analyzer": "standard"
},
"kubernetes": {
"properties": {
"namespace": { "type": "keyword" },
"pod_name": { "type": "keyword" },
"container_name": { "type": "keyword" },
"labels": { "type": "object" }
}
},
"trace_id": {
"type": "keyword"
},
"span_id": {
"type": "keyword"
},
"http": {
"properties": {
"method": { "type": "keyword" },
"status_code": { "type": "integer" },
"path": { "type": "keyword" },
"response_time_ms": { "type": "float" }
}
}
},
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword",
"ignore_above": 1024
}
}
}
]
}
}
}ISM(索引状态管理)策略
ISM 策略自动管理索引生命周期。
json
PUT _plugins/_ism/policies/logs-lifecycle
{
"policy": {
"description": "Log index lifecycle management",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [
{
"rollover": {
"min_index_age": "1d",
"min_primary_shard_size": "30gb"
}
}
],
"transitions": [
{
"state_name": "warm",
"conditions": {
"min_index_age": "7d"
}
}
]
},
{
"name": "warm",
"actions": [
{
"warm_migration": {},
"replica_count": {
"number_of_replicas": 0
},
"force_merge": {
"max_num_segments": 1
}
}
],
"transitions": [
{
"state_name": "cold",
"conditions": {
"min_index_age": "30d"
}
}
]
},
{
"name": "cold",
"actions": [
{
"cold_migration": {
"timestamp_field": "@timestamp"
}
}
],
"transitions": [
{
"state_name": "delete",
"conditions": {
"min_index_age": "90d"
}
}
]
},
{
"name": "delete",
"actions": [
{
"delete": {}
}
]
}
],
"ism_template": [
{
"index_patterns": ["logs-*"],
"priority": 100
}
]
}
}索引别名
json
# Create alias for rollover
PUT logs-production-000001
{
"aliases": {
"logs-production": {
"is_write_index": true
},
"logs-production-read": {}
}
}
# Query alias
GET _alias/logs-production
# Manual rollover (for testing)
POST logs-production/_rollover
{
"conditions": {
"max_age": "1d",
"max_primary_shard_size": "30gb"
}
}数据采集
从 FluentBit 直接采集到 OpenSearch
yaml
# fluent-bit-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: logging
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
Daemon off
Parsers_File parsers.conf
HTTP_Server On
HTTP_Listen 0.0.0.0
HTTP_Port 2020
[INPUT]
Name tail
Tag kube.*
Path /var/log/containers/*.log
Parser docker
DB /var/log/flb_kube.db
Mem_Buf_Limit 50MB
Skip_Long_Lines On
Refresh_Interval 10
[FILTER]
Name kubernetes
Match kube.*
Kube_URL https://kubernetes.default.svc:443
Kube_CA_File /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Kube_Token_File /var/run/secrets/kubernetes.io/serviceaccount/token
Merge_Log On
K8S-Logging.Parser On
K8S-Logging.Exclude On
[FILTER]
Name modify
Match *
Add cluster_name eks-production
Add environment production
[OUTPUT]
Name opensearch
Match *
Host vpc-logs-production-xxxxx.ap-northeast-2.es.amazonaws.com
Port 443
TLS On
AWS_Auth On
AWS_Region ap-northeast-2
Index logs-production
Type _doc
Logstash_Format On
Logstash_Prefix logs-production
Retry_Limit 5
Buffer_Size 5MB
Generate_ID On
# Compression saves network costs
Compress gzip
parsers.conf: |
[PARSER]
Name docker
Format json
Time_Key time
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
[PARSER]
Name json
Format json
Time_Key timestamp
Time_Format %Y-%m-%dT%H:%M:%S.%LZFluentBit DaemonSet(使用 IRSA)
yaml
# fluent-bit-daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
labels:
app: fluent-bit
spec:
selector:
matchLabels:
app: fluent-bit
template:
metadata:
labels:
app: fluent-bit
spec:
serviceAccountName: fluent-bit
tolerations:
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
- operator: Exists
effect: NoExecute
- operator: Exists
effect: NoSchedule
containers:
- name: fluent-bit
image: public.ecr.aws/aws-observability/aws-for-fluent-bit:2.31.12
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: fluent-bit-config
mountPath: /fluent-bit/etc/
env:
- name: AWS_REGION
value: ap-northeast-2
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: fluent-bit-config
configMap:
name: fluent-bit-config
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluent-bit
namespace: logging
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/FluentBitOpenSearchRole通过 Kinesis Data Firehose 采集
hcl
# firehose.tf
resource "aws_kinesis_firehose_delivery_stream" "opensearch" {
name = "logs-to-opensearch"
destination = "opensearch"
opensearch_configuration {
domain_arn = aws_opensearch_domain.main.arn
role_arn = aws_iam_role.firehose.arn
index_name = "logs"
index_rotation_period = "OneDay"
buffering_interval = 60
buffering_size = 5
retry_duration = 300
vpc_config {
subnet_ids = data.aws_subnets.private.ids
security_group_ids = [aws_security_group.firehose.id]
role_arn = aws_iam_role.firehose_vpc.arn
}
cloudwatch_logging_options {
enabled = true
log_group_name = aws_cloudwatch_log_group.firehose.name
log_stream_name = "opensearch-delivery"
}
s3_configuration {
role_arn = aws_iam_role.firehose.arn
bucket_arn = aws_s3_bucket.backup.arn
prefix = "failed/"
buffering_size = 10
buffering_interval = 400
compression_format = "GZIP"
}
}
}OpenSearch Dashboards
Dashboard 访问设置
bash
# SSH tunnel (for dev/test)
ssh -i key.pem -L 9200:vpc-logs-production-xxx.ap-northeast-2.es.amazonaws.com:443 ec2-user@bastion
# Or access via ALB (recommended for production)创建索引模式
1. Access OpenSearch Dashboards
2. Management > Stack Management > Index Patterns
3. Click "Create index pattern"
4. Index pattern: logs-*
5. Time field: @timestamp
6. Click "Create index pattern"搜索查询示例
json
# Search error logs
GET logs-*/_search
{
"query": {
"bool": {
"must": [
{ "match": { "level": "error" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
],
"filter": [
{ "term": { "kubernetes.namespace": "production" } }
]
}
},
"sort": [
{ "@timestamp": { "order": "desc" } }
],
"size": 100
}
# Aggregation query - errors by namespace
GET logs-*/_search
{
"size": 0,
"query": {
"range": {
"@timestamp": { "gte": "now-24h" }
}
},
"aggs": {
"by_namespace": {
"terms": {
"field": "kubernetes.namespace",
"size": 20
},
"aggs": {
"by_level": {
"terms": {
"field": "level",
"size": 5
}
}
}
}
}
}
# Response time percentiles
GET logs-*/_search
{
"size": 0,
"query": {
"bool": {
"must": [
{ "exists": { "field": "http.response_time_ms" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
]
}
},
"aggs": {
"response_time_percentiles": {
"percentiles": {
"field": "http.response_time_ms",
"percents": [50, 75, 90, 95, 99]
}
}
}
}创建可视化
# Pie Chart: Log level distribution
1. Visualize > Create visualization > Pie
2. Index pattern: logs-*
3. Buckets > Split slices > Terms > level
4. Save
# Line Chart: Errors over time
1. Visualize > Create visualization > Line
2. Index pattern: logs-*
3. Y-axis: Count
4. X-axis: Date Histogram > @timestamp
5. Add filter: level: error
6. Save
# Data Table: Top error messages
1. Visualize > Create visualization > Data table
2. Index pattern: logs-*
3. Bucket: Terms > message.keyword (Top 10)
4. Add filter: level: error
5. Save安全配置
细粒度访问控制(FGAC)
json
# Create role
PUT _plugins/_security/api/roles/logs-reader
{
"cluster_permissions": [
"cluster_composite_ops_ro"
],
"index_permissions": [
{
"index_patterns": ["logs-*"],
"allowed_actions": [
"read",
"search"
]
}
]
}
# Role mapping (IAM role)
PUT _plugins/_security/api/rolesmapping/logs-reader
{
"backend_roles": [
"arn:aws:iam::123456789012:role/DeveloperRole"
],
"users": [
"developer@example.com"
]
}
# Admin role
PUT _plugins/_security/api/roles/logs-admin
{
"cluster_permissions": [
"cluster_all"
],
"index_permissions": [
{
"index_patterns": ["logs-*"],
"allowed_actions": ["indices_all"]
}
]
}文档级安全(DLS)
json
# Role that can only access specific namespace
PUT _plugins/_security/api/roles/team-a-logs
{
"cluster_permissions": [
"cluster_composite_ops_ro"
],
"index_permissions": [
{
"index_patterns": ["logs-*"],
"dls": "{\"bool\": {\"must\": [{\"term\": {\"kubernetes.namespace\": \"team-a\"}}]}}",
"allowed_actions": ["read", "search"]
}
]
}字段级安全(FLS)
json
# Hide sensitive fields
PUT _plugins/_security/api/roles/logs-restricted
{
"cluster_permissions": [
"cluster_composite_ops_ro"
],
"index_permissions": [
{
"index_patterns": ["logs-*"],
"fls": ["~user_id", "~ip_address", "~session_token"],
"allowed_actions": ["read", "search"]
}
]
}SAML 身份验证设置
yaml
# opensearch-security-config.yaml
config:
dynamic:
authc:
saml_auth_domain:
enabled: true
order: 1
http_authenticator:
type: saml
challenge: true
config:
idp:
metadata_url: https://example.okta.com/app/xxx/sso/saml/metadata
entity_id: http://www.okta.com/xxx
sp:
entity_id: https://vpc-logs-production-xxx.ap-northeast-2.es.amazonaws.com
kibana_url: https://vpc-logs-production-xxx.ap-northeast-2.es.amazonaws.com/_dashboards
roles_key: Role
exchange_key: your-exchange-key
authentication_backend:
type: noop成本优化
存储分层
Hot (EBS gp3) -> UltraWarm -> Cold Storage (S3)
| | |
Day 0-7 Day 7-30 Day 30-90
| | |
Fast queries Read-only Archive
High cost Medium cost Low cost成本比较(基于每天 100GB)
+-----------------+--------------+--------------+--------------+
| Storage Tier | Retention | Monthly Cost | Cost per GB |
+-----------------+--------------+--------------+--------------+
| Hot (EBS gp3) | 7 days | ~$500 | $0.10/GB |
| UltraWarm | 23 days | ~$350 | $0.024/GB |
| Cold Storage | 60 days | ~$120 | $0.01/GB |
+-----------------+--------------+--------------+--------------+
| Total (90-day) | | ~$970/mo | |
| Hot only | 90 days | ~$2,700/mo | |
| Savings | | ~$1,730/mo | 64% saved |
+-----------------+--------------+--------------+--------------+索引优化
json
# Compression settings
PUT logs-*/_settings
{
"index": {
"codec": "best_compression"
}
}
# Adjust refresh interval (during ingestion)
PUT logs-*/_settings
{
"index": {
"refresh_interval": "30s"
}
}
# Disable unnecessary fields
PUT _index_template/logs-optimized
{
"index_patterns": ["logs-*"],
"template": {
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"message": {
"type": "text",
"norms": false,
"index_options": "docs"
}
}
}
}
}预留实例
bash
# RI purchase recommendations
# - Purchase RI if planning to use for 1+ years
# - All Upfront option is cheapest (up to 36% savings)
# - Partial Upfront: 24% savings
# - No Upfront: 21% savings大规模日志环境中的限制
OpenSearch 擅长全文搜索,但当日志量快速增长时会出现结构性限制。
倒排索引的低效性
| 方面 | OpenSearch(倒排索引) | ClickHouse(列式) |
|---|---|---|
| 压缩比 | 大小增加 1.5-2 倍(包括索引) | 相比原始数据压缩 5-10 倍 |
| 聚合查询 | 需要扫描完整文档 | 快速的列级扫描 |
| 存储成本 | 高(索引 + 原始数据) | 低(列式压缩) |
| INSERT 成本 | 索引 CPU 开销高 | 轻量级列式追加 |
聚合查询性能下降
对于日志分析中常用的聚合查询(最近一小时的 ERROR 计数、按 Service 划分的错误率等),OpenSearch 必须读取所有匹配的文档,随着数据量增长,性能会急剧下降。
Query: "Aggregate ERROR log count by service for the last hour"
OpenSearch: Look up document IDs from index → Read each document → Aggregate
100GB scale: ~2s / 1TB scale: ~25s / 10TB scale: timeout
ClickHouse: Scan only timestamp, level, service columns → Aggregate
100GB scale: ~0.3s / 1TB scale: ~1s / 10TB scale: ~8s扩展成本问题
| 每日日志量 | OpenSearch 每月成本(估计) | ClickHouse 每月成本(估计) | 比率 |
|---|---|---|---|
| 100GB | ~$970 | ~$400 | 2.4x |
| 500GB | ~$4,500 | ~$1,200 | 3.8x |
| 1TB | ~$9,000 | ~$2,000 | 4.5x |
| 10TB | ~$80,000+ | ~$10,000 | 8x+ |
关键洞察:分析日志查询模式时,大多数环境中超过 90% 的查询基于“时间范围 + 字段条件”。与倒排索引相比,列式存储处理此模式的效率要高得多。
迁移到 ClickHouse 的决策标准
使用以下标准确定是保留 OpenSearch,还是考虑迁移到 ClickHouse。
| 标准 | 保留 OpenSearch | 考虑 ClickHouse |
|---|---|---|
| 每日日志量 | 少于 100GB | 超过 100GB |
| 主要查询模式 | 全文搜索(基于关键字) | 时间范围 + 字段条件 |
| 聚合查询占比 | 低(占总数的 20% 以下) | 高(占总数的 50% 以上) |
| 成本敏感性 | 低 | 高 |
| 全文搜索需求 | 必不可少(核心功能) | 可选(有更好,没有也行) |
| 团队 SQL 熟练度 | 低 | 高 |
迁移注意事项:
Phase 1: Query Pattern Analysis (2 weeks)
└── Analyze actual query logs for full-text search vs field-condition query ratio
Phase 2: Parallel Operation (1-2 months)
└── Dual-write same logs to both OpenSearch + ClickHouse
└── Compare query performance and costs
Phase 3: Gradual Migration
└── Aggregation/dashboard queries → Migrate to ClickHouse first
└── Queries requiring full-text search → Keep OpenSearch or use ClickHouse tokenbf index与 Loki 的比较
功能比较
| 功能 | OpenSearch | Loki |
|---|---|---|
| 全文搜索 | 出色(基于 Lucene) | 有限(labels+grep) |
| 查询语言 | Query DSL、SQL | LogQL |
| 索引 | 全文 | 仅 labels |
| 存储成本 | 高 | 低(对象存储) |
| 复杂聚合 | 出色 | 基础 |
| Dashboard | OpenSearch Dashboards | Grafana |
| 运维复杂度 | 高 | 低 |
| 可扩展性 | 水平 | 水平 |
| 多租户 | FGAC | 原生 |
按使用场景的建议
OpenSearch recommended:
+-- Full-text search is required
+-- Complex analytics/aggregation queries needed
+-- Compliance requirements (audit logs)
+-- Security analytics (SIEM)
+-- Migrating from existing ELK stack
Loki recommended:
+-- Cost is top priority
+-- Already using Grafana
+-- Simple log search/filtering
+-- Need Prometheus integration
+-- Want to reduce operational burden迁移注意事项
yaml
# Migrating from Loki to OpenSearch
considerations:
- Query rewriting needed (LogQL -> Query DSL)
- Dashboard rebuild (Grafana -> OpenSearch Dashboards)
- Index template/mapping design
- Expected cost increase (3-5x)
- Increased operational complexity
# Migrating from OpenSearch to Loki
considerations:
- Loss of full-text search capabilities
- Limited complex aggregation queries
- Existing dashboard/alert rebuild
- Cost savings (60-80%)
- Operational simplification测验
通过 OpenSearch 测验 测试你的知识。