【发布时间】:2012-09-22 00:19:10
【问题描述】:
有没有办法只在 MongoDB 中的部分字段上创建索引,例如在前 10 个字符上?我找不到它的文档(或在此处询问)。
MySQL 等价物是 CREATE INDEX part_of_name ON customer (name(10));。
原因:我有一个包含单个字段的集合,该字段的长度从几个字符到 1000 多个字符不等,平均 50 个字符。由于有大约一亿个文档,因此很难将完整的索引放入内存中(根据统计数据,使用 8% 的数据进行测试,索引已经是 400MB)。仅对字段的第一部分进行索引将使索引大小减少约 75%。在大多数情况下,搜索词很短,不是全文搜索。
解决方法是为每个项目添加 10 个(小写)字符的第二个字段,为其编制索引,然后添加逻辑以在搜索词超过 10 个字符时过滤结果(以及该额外字段 is probably needed anyway对于不区分大小写的搜索,除非有人有更好的方法)。不过,这似乎是一种丑陋的做法。
[稍后添加]
我尝试添加第二个字段,其中包含来自主字段的前 12 个字符,小写。这不是一个很大的成功。
以前,平均对象大小为 50 字节,但我忘了包括 _id 和其他开销,所以我的主要字段长度(只有一个)平均接近 30 字节而不是 50。然后,第二个字段索引包含_id 和其他开销。
净结果(对于我的 8% 样本)是主字段上的索引是 415MB,而 12 字节字段上的索引是 330MB - 只节省了 20% 的空间,不值得。我可以复制整个字段(以解决不区分大小写的搜索问题),但实际上我应该重新考虑 MongoDB 是否适合这项工作(或者只是购买更多内存并使用两倍的磁盘空间)。
[后来添加]
这是一个典型的文档,包含源字段和短小写的字段:
{ "_id" : ObjectId("505d0e89f56588f20f000041"), "q" : "Continental Airlines", "f" : "continental " }
索引:
db.test.ensureIndex({q:1});
db.test.ensureIndex({f:1});
在较短的字段上工作的“f”索引是“q”索引大小的 80%。我并不是要暗示我在索引中包含了 _id,只是它需要使用它在某个地方显示索引将指向的位置,因此这是一种开销,可能有助于解释为什么较短的键没有什么区别。
对索引的访问基本上是随机的,它的任何部分都比其他任何部分更有可能被访问。完整文件的总索引大小可能为 5GB,因此对于该索引来说并不是极端的。为其他搜索案例添加一些其他字段,以及它们的相关索引,以及小写的数据副本,确实开始加起来,并使分页和交换更有可能(它是一个 8GB 服务器),这就是我开始研究更多简洁的索引。
【问题讨论】:
-
FWIW,您可能会使用 Solr 之类的东西进行文本搜索;我将它与 MongoDB 一起使用来进行文档搜索,而且效果很好。我让 Solr 擅长它擅长的事情,让 Mongo 擅长它擅长的事情。
-
是的,克里斯,这就是我关于重新考虑 Mongo 是否是适合这项工作的工具的评论的意思 - Mongo 没有问题(加载和索引真的很快!),只是这不是什么它非常适合(尤其是当我添加更复杂的搜索时)。 Elasticsearch 位居榜首。
-
8GB 可能无法满足此用例的需求,除非您打算使用外部文本引擎。你说得对:全文搜索目前还不是 MongoDB 的强项之一。