ElasticSearch(3) - 慢查询优化思路

ES 的慢查询可能会导致性能瓶颈,影响系统的响应时间和用户体验。要优化 ES 查询性能,可以从查询语句和表结构两个方面入。

查询语句优化角度,可以优化查询类型、合理使用fliter、限制字段返回等都是有效的方法。

表结构优化角度,选择合适的字段类型、合理设置索引、优化分片和副本设置等也是提高性能的关键。

1. 查询语句优化

1.1 使用合适的查询类型
  • 精确匹配(Term Query)

    • 对于精确值匹配,使用 term 查询而不是 match 查询。term 查询适用于不分词的字段,例如 ID、状态码等。

    • 示例:

      {
        "query": {
          "term": {
            "status": "active"
          }
        }
      }
      
  • 避免使用通配符(Wildcard Query)

    • wildcard 查询会导致全表扫描,性能较差。如果必须使用,尽量在字段上使用 keyword 类型或使用前缀查询(prefix)。

    • 示例:

      {
        "query": {
          "wildcard": {
            "field": "value*"
          }
        }
      }
      
  • 避免使用正则表达式(Regexp Query)

    • 正则表达式查询通常非常慢。尽量避免或优化正则表达式。
  • 合理使用布尔查询(Bool Query)

    • 使用 bool 查询结合多个子查询时,确保使用 must, should, must_not 等子句进行合理的组合。

    • 示例:

      {
        "query": {
          "bool": {
            "must": [
              { "match": { "field1": "value1" } },
              { "range": { "field2": { "gte": 10 } } }
            ],
            "should": [
              { "term": { "field3": "value2" } }
            ],
            "must_not": [
              { "term": { "field4": "value3" } }
            ]
          }
        }
      }
      
  • 分页优化

    • 避免使用深分页(fromsize 的组合)。使用 scroll API 或 search_after 实现高效分页。

    • 示例(使用 search_after):

      {
        "query": {
          "match_all": {}
        },
        "sort": [
          { "timestamp": "asc" }
        ],
        "search_after": [ "2023-09-01T00:00:00" ]
      }
      
1.2 限制字段返回
  • 只返回需要的字段

    • 使用 _source 参数限制返回的字段,避免检索不必要的字段。

    • 示例:

      {
        "_source": ["field1", "field2"],
        "query": {
          "match_all": {}
        }
      }
      
1.3 使用过滤器
  • 过滤器而非查询

    • 对于不需要计算相关性的查询,使用filter而不是query,因为过滤器更高效且缓存友好。

    • 示例:

      {
        "query": {
          "bool": {
            "filter": [
              { "term": { "status": "active" } },
              { "range": { "date": { "gte": "2023-01-01" } } }
            ]
          }
        }
      }
      
1.4 使用聚合
  • 优化聚合查询

    • 对于复杂的聚合查询,使用 aggs 进行聚合,避免在查询中包含复杂的计算。

    • 示例:

      {
        "aggs": {
          "status_count": {
            "terms": {
              "field": "status.keyword"
            }
          }
        }
      }
      

2. 表结构优化

2.1 适当设计字段类型
  • 选择合适的数据类型

    • 根据数据的特点选择合适的字段类型,如 textkeywordintegerdate 等。text 类型适合全文搜索,keyword 适合精确匹配。

    • 示例:

      {
        "mappings": {
          "properties": {
            "status": {
              "type": "keyword"
            },
            "description": {
              "type": "text"
            }
          }
        }
      }
      
2.2 使用合适的索引
  • 使用 keyword 类型索引

    • 对于需要进行精确匹配的字段,使用 keyword 类型,这样可以提高查询性能。

    • 示例:

      {
        "mappings": {
          "properties": {
            "status": {
              "type": "keyword"
            }
          }
        }
      }
      
2.3 合理设置分片
  • 分片和副本设置

    • 根据数据量和查询负载合理设置分片数量。更多的分片可以提高并发查询的性能,但也可能增加管理开销。副本数设置可以提高查询性能和容错能力。

      • 一般控制每个分片占用的硬盘容量不超过32G(与Java使用的内存指针压缩技术有关)
      • 为了防止节点故障时丢失太多数据,一般分片数也不超过节点数的3倍
    • 示例:

      {
        "settings": {
          "index": {
            "number_of_shards": 3,
            "number_of_replicas": 1
          }
        }
      }
      
2.4 字段数据类型优化
  • 避免使用动态映射

    • 动态映射可能会创建不必要的字段,增加存储和查询的复杂度。使用显式映射定义字段类型。

    • 示例:

      {
        "mappings": {
          "properties": {
            "field1": {
              "type": "text"
            }
          }
        }
      }
      
2.5 数据建模
  • 优化数据建模

    • 对于复杂查询,可以考虑将数据建模为更适合查询的结构。例如,使用嵌套对象和子文档来优化查询。

    • 示例:

      {
        "mappings": {
          "properties": {
            "user": {
              "properties": {
                "name": { "type": "text" },
                "age": { "type": "integer" }
              }
            }
          }
        }
      }
      
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川涂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值