elasticsearch - 路由VS. 索引查询性能

use*_*226 10 elasticsearch

我正计划在日期和用户指导中查询数百万个文档的策略.

  • 选项1 - 按用户索引.按日期路由.
  • 选项2 - 按日期编制索引.用户路由.

使用路由或索引时有什么区别或优势?

小智 19

Shay Banon @ Elasticsearch推荐的设计模式之一是:按时间范围索引,按用户路由和使用别名.

为每天(或日期范围)创建索引并在用户字段上路由文档,这样您就可以"淘汰"旧日志,并且不需要在所有分片上执行查询:

$ curl -XPOST localhost:9200/user_logs_20140418 -d '{
    "mappings" : {
        "user_log" : {
            "_routing": {
              "required": true,
              "path": "user"
            },
            "properties" : {
              "user" : { "type" : "string" },
              "log_time": { "type": "date" }
            }
        }
    }
}'
Run Code Online (Sandbox Code Playgroud)

创建别名以过滤和路由用户,这样您就可以查询用户'foo'的文档:

$ curl -XPOST localhost:9200/_aliases -d '{
  "actions": [{
    "add": {
      "alias": "user_foo",
      "filter": {"term": {"user": "foo"}},
      "routing": "foo"
    }
  }]
}'
Run Code Online (Sandbox Code Playgroud)

为时间窗创建别名,这样您就可以查询文档'this_week':

$ curl -XPOST localhost:9200/_aliases -d '{
  "actions": [{
    "add": {
      "index": ["user_logs_20140418", "user_logs_20140417", "user_logs_20140416", "user_logs_20140415", "user_logs_20140414"],
      "alias": "this_week"
    }, 
    "remove": {
      "index": ["user_logs_20140413", "user_logs_20140412", "user_logs_20140411", "user_logs_20140410", "user_logs_20140409", "user_logs_20140408", "user_logs_20140407"],
      "alias": "this_week"
    }
  }]
}'
Run Code Online (Sandbox Code Playgroud)

这种方法的一些优点:

  • 如果您使用别名搜索用户,则只会搜索用户数据所在的分片
  • 如果用户的数据增长,您可以考虑为该用户创建单独的索引(您只需将该用户的别名指向新索引)
  • 没有分析过度分配的性能影响
  • 您可以通过简单关闭(当您关闭索引时,它们几乎不消耗任何资源)或删除整个索引来"退出"旧日志(删除索引比删除索引中的文档更简单)


Bla*_*POP 7

索引编制是对您建立索引的文档[ 倒置索引 ] 进行解析[标记化,筛选后]的过程。就像教科书的附录。

当索引数据超过一个服务器限制时。与其升级服务器配置,不如添加另一台服务器并与它们共享数据。此过程称为分片

如果我们搜索它,它将搜索所有分片并执行地图缩小并返回结果。如果我们将相似数据分组在一起并在特定数据中搜索某些数据,则意味着降低处理能力并提高了速度。

路由用于存储特定碎片中的数据组。选择要路由的字段。该字段应出现在所有文档中,该字段不应包含不同的值。

注意:路由应在多分片环境中使用(而不是在单个节点中)。如果我们在单节点中使用路由,则不会使用它。

  • 路由使用多个分片是有意义的,这是事实。另一方面,多个分片不一定意味着多个节点,尽管您可以根据需要轻松扩展,只需添加节点即可。 (5认同)

小智 5

让我们首先定义术语。

在 Elasticsearch 的上下文中,索引可能意味着很多事情:

  • 索引文档:将新文档写入 Elasticsearch
  • 索引字段:将映射(模式)中的字段定义为索引。您搜索的所有字段都需要建立索引(默认情况下所有字段都建立索引)
  • Elasticsearch 索引:这是一个配置单元(例如模式/映射)和数据单元(即磁盘上的一些文件)。从某种意义上说,它就像一个数据库,将文档写入索引。当您搜索时,您可以访问一个或多个索引
  • Lucene索引:一个Elasticsearch索引可以分为N个分片。分片是 Lucene 索引。当您索引文档时,该文档将被路由到其中一个分片。当您在索引中搜索时,搜索结果将广播到每个分片的副本。每个分片都会回复它所知道的内容,然后汇总结果并将其发送回客户端

从上下文来看,“按用户索引”和“按日期索引”是指每个用户有一个索引或每个日期间隔(例如天)有一个索引。

正如我之前所描述的,路由是指将文档发送到分片。默认情况下,这是相当随机地完成的:哈希范围除以分片数量。当文档传入时,Elasticsearch 会对其_id. 哈希值属于其中一个分片的哈希范围 ==> 这就是文档所在的位置。

您可以使用自定义路由来控制这一点:_idElasticsearch 可以对路由值(例如用户名)进行哈希处理,而不是对 进行哈希处理。结果,具有相同路由值(即相同用户)的所有文档都落在同一个分片上。然后可以在查询时使用路由,以便 Elasticsearch 仅查询一个分片(每个索引)而不是 N 个分片。这可以带来巨大的查询性能提升(特别查看幻灯片 24)。

回到当前的问题,我将其视为“通过索引或使用路由来分解数据时有什么区别或优势?”

为了回答这个问题,该策略应考虑到:

  • 索引索引(写入)是如何完成的。如果有大量索引,则需要确保所有节点都参与(即在相同数量的分片上写入相似数量的数据),否则会出现瓶颈
  • 如何查询数据。如果查询经常引用单个用户的数据,那么已经按用户细分的数据会很有用(每个用户的索引或按用户的路由)
    • 分片总数。拥有的分片、节点和字段越多,集群状态就越大。如果集群状态大小变大(例如大于几十MB),则在所有节点上保持同步变得更加困难,从而导致集群不稳定。根据经验,您希望单个 Elasticsearch 集群中的数千个分片保持在几十个以内

在实践中,我见过以下设计:

  1. 每个固定时间间隔一个索引。您将在日志中看到这一点(例如,Logstash 默认情况下写入每日索引)
  2. 每个时间间隔一个索引,按 size 旋转。即使写入吞吐量变化,这也能保持恒定的索引大小
  3. 每个用户一个索引“系列”(1. 或 2.)。如果用户很少,这很有效,因为它消除了过滤。但它不适用于许多用户,因为你有太多的分片
  4. 每个时间间隔(1 或 2)一个索引,包含大量分片并按用户进行路由。如果您有很多用户,这很有效。正如 Mahesh 指出的那样,如果某些用户拥有大量数据,导致分片不均匀,就会出现问题。在这种情况下,您需要一种方法将大用户重新索引到他们自己的索引中(参见图 3),并且您可以使用别名来对应用程序隐藏此逻辑。

我还没有看到每个用户一个索引并按日期间隔路由的设计。这里的主要缺点是您可能一次写入一个分片(包含今天哈希的分片)。这将限制您的写入吞吐量和平衡写入的能力。但也许这种设计对于大量但不是大量的用户(例如 1K)、有限的时间间隔内很少写入和大量查询来说效果很好。

顺便说一句,如果您想了解更多有关这些内容的信息,我们有一个Elasticsearch 操作培训,我们在其中讨论了很多有关架构、权衡以及 Elasticsearch 幕后工作方式的内容。(披露:我讲授这门课)