【问题标题】:MongoDB "filtered" index: is it possible?MongoDB“过滤”索引:有可能吗?
【发布时间】:2013-09-01 12:54:46
【问题描述】:

是否可以“仅当”要索引的字段之一具有特定值时才索引集合的某些文档?

让我用一个例子来解释:

“posts”集合有数百万个文档,全部定义如下:

{ “网络”:“网络_1”, "blogname": "blogname_1", “post_id”:1234, “post_slug”:“abcdefg” }

假设帖子的分布在 network_1 和 network_2 上平均分配

我的应用程序经常根据“network”的值选择查询类型(尽管有时我需要来自两个网络的数据):

例如:

www.test.it/network_1/blog_1/**postid**/1234/
 -> db.posts.find ({network: "network_1" blogname "blog_1", post_id: 1234})

www.test.it/network_2/blog_4/**slug**/aaaa/
 -> db.posts.find ({network: "network_2" blogname "blog_4" post_slug: "yyyy"})

我可以创建两个单独的索引(network / blogname / post_id 和 network / blogname / post_slug),但我会浪费大量内存,因为索引中 50% 的数据永远不会被使用。

有没有办法创建一个“过滤”的索引?

示例: (注意 WHERE 参数)

db.posts.ensureIndex ({network: 1 blogname: 1, post_id: 1}, {where: {network: "network_1"}})

db.posts.ensureIndex ({network: 1 blogname: 1, post_slug: 1}, {where: {network: "network_2"}})

【问题讨论】:

  • 这在 MongoDB 中尚不可能

标签: mongodb indexing


【解决方案1】:

在 MongoDB 3.2+ 中确实有可能,他们称之为 partialFilterExpression,您可以在其中根据将创建的索引设置条件。

示例

db.users.createIndex({ "userId": 1, "project": 1 }, 
{ unique: true, partialFilterExpression:{ 
  userId: { $exists: true, $gt : { $type : 10 } } } })

请参阅Partial Index 文档

【讨论】:

    【解决方案2】:

    从 MongoDB v3.2 开始,支持部分索引。文档:https://docs.mongodb.org/manual/core/index-partial/

    【讨论】:

      【解决方案3】:

      这是可能的,但它需要一种解决方法,这会在您的文档中创建冗余,需要您重写您的查找查询并将查找查询限制为完全匹配。

      MongoDB 支持sparse indexes,它只索引给定字段存在的文档。您可以通过将此字段仅添加到您想要索引的文档中来使用此功能来仅索引集合的一部分。

      坏消息是稀疏索引只能包含一个字段。但好消息是,该字段还可以包含一个具有多个字段的对象,因此您仍然可以在该字段中存储您要搜索的所有数据。

      为此,请在包含的文档中添加一个新字段,其中包含一个包含您搜索的字段的对象:

      {
          "network": "network_1",
          "blogname": "blogname_1",
          "post_id": 1234,
          "post_slug": "abcdefg"
          "network_1_index_key": {
              "blogname": "blogname_1",
              "post_id": 1234
          }
      }
      

      您的 ensureIndex 命令将索引字段 network_1_index_key:

       db.posts.ensureIndex( { network_1_index_key: 1 }, { sparse: true } )
      

      应该使用此索引的查找查询现在必须查询字段 network_1_index_key 的确切对象:

       db.posts.find ({ 
                          network_1_index_key: { 
                              blogname: "blogname_1", 
                              post_id: 1234 
                          } 
                      })
      

      只有当您要索引的文档只是集合的一小部分时,这样做才有意义。当它大约一半时,我会创建一个常规索引并使用它,因为更大的文档大小可以减轻减少索引大小带来的收益。

      【讨论】:

      • 我认为您的建议现在是唯一可能的解决方案,但我需要更新数百万个现有文档并检查工作集是否适合 RAM
      • @Ligio 也许一些服务器端的javascript可以完成这项工作?当您在转换大量文档时遇到任何问题时,您应该创建一个新问题。
      • 这个答案因partialFilterExpression 的引入而被弃用(参见其他答案,MongoDB 3.2+)
      【解决方案4】:

      您可以尝试在所有字段(network / blogname / post_id / post_slug)上创建索引

      【讨论】:

      • 但这正是 Ligio 想要避免的。
      • 索引“network / blogname / post_id / post_slug”不会涵盖“network / blogname / post_slug”上的发现
      • 我在我的收藏中创建了相同的索引,它对我有用。您可以发送有关您的收藏的信息吗? db.posts.stats() 和 db.posts.find ({network: "network_1" blogname "blog_1", post_id: 1234}).explain() ?
      • Philipp,Ligio 希望避免创建两个索引。
      猜你喜欢
      • 2015-10-24
      • 1970-01-01
      • 2011-08-21
      • 2018-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多