无法在mongodb中创建索引,"键太大而不能索引"

San*_*rya 28 mongodb mongodb-query

我在mongodb创建索引,有1000万条记录但是跟着错误

db.logcollection.ensureIndex({"Module":1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 3,
        "ok" : 0,
        "errmsg" : "Btree::insert: key too large to index, failing play.logcollection.$Module_1 1100 { : \"RezGainUISystem.Net.WebException: The request was aborted: The request was canceled.\r\n   at System.Net.ConnectStream.InternalWrite(Boolean async, Byte...\" }",
        "code" : 17282
}
Run Code Online (Sandbox Code Playgroud)

请帮我看看如何在mongodb中创建索引,

anh*_*hlc 39

如果现有文档的索引条目超出索引键限制(1024字节),MongoDB将不会在集合上创建索引.但是,您可以创建散列索引文本索引:

db.logcollection.createIndex({"Module":"hashed"})
Run Code Online (Sandbox Code Playgroud)

要么

db.logcollection.createIndex({"Module":"text"})
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,它对我有用但散列索引的性能非常慢,我的查询是db.logcollection.find({"Module":"RezGainUI"}).count().计算大约需要18秒 (2认同)
  • 找到超长值并尽可能缩短它们.然后你可以创建正常的索引 (2认同)

Rus*_*m K 22

您可以使用以下命令启动mongod实例来沉默此行为:

mongod --setParameter failIndexKeyTooLong=false
Run Code Online (Sandbox Code Playgroud)

或者从mongoShell执行以下命令

db.getSiblingDB('admin').runCommand( { setParameter: 1, failIndexKeyTooLong: false } )
Run Code Online (Sandbox Code Playgroud)

如果你确保你的字段很少超过限制,那么解决这个问题的一种方法是将你的字段(导致索引超出限制)拆分为逐字节长度<1KB,例如对于字段val我会将其拆分为元组字段val_1,val_2等等.Mongo将文本存储为utf-8有效值.这意味着您需要一个可以正确拆分utf-8字符串的函数.

   def split_utf8(s, n):
    """
    (ord(s[k]) & 0xc0) == 0x80 - checks whether it is continuation byte (actual part of the string) or jsut header indicates how many bytes there are in multi-byte sequence

    An interesting aside by the way. You can classify bytes in a UTF-8 stream as follows:

    With the high bit set to 0, it's a single byte value.
    With the two high bits set to 10, it's a continuation byte.
    Otherwise, it's the first byte of a multi-byte sequence and the number of leading 1 bits indicates how many bytes there are in total for this sequence (110... means two bytes, 1110... means three bytes, etc).
    """
    s = s.encode('utf-8')
    while len(s) > n:
        k = n
        while (ord(s[k]) & 0xc0) == 0x80:
            k -= 1
        yield s[:k]
        s = s[k:]
    yield s
Run Code Online (Sandbox Code Playgroud)

然后你可以定义你的复合索引:

db.coll.ensureIndex({val_1: 1, val_2: 1, ...}, {background: true})
Run Code Online (Sandbox Code Playgroud)

或每个多个索引val_i:

db.coll.ensureIndex({val_1: 1}, {background: true})
db.coll.ensureIndex({val_1: 2}, {background: true})
...
db.coll.ensureIndex({val_1: i}, {background: true})
Run Code Online (Sandbox Code Playgroud)

重要提示:如果考虑在复合索引中使用您的字段,请注意split_utf8函数的第二个参数.在每个文档中,您需要删除构成索引键的每个字段值的字节总和,例如索引(a:1,b:1,val:1)1024 - sizeof(value(a)) - sizeof(value(b))

在任何其他情况下,使用散列文本索引.


kev*_*adi 8

正如不同的人在答案中指出的那样,该错误key too large to index表示您试图在长度超过1024个字节的一个或多个字段上创建索引。

用ASCII术语,通常1024个字节转换为大约1024个字符的长度。

没有办法解决这个,因为这是在提到的MongoDB中设置一个内部限制的MongoDB限制和阈值页面

索引条目的总大小(小于BSON类型,可能包括结构开销)必须小于1024个字节。

failIndexKeyTooLong服务器参数手册页中所述,打开错误不是解决方案:

...这些操作将成功插入或修改文档,但一个或多个索引将不包含对该文档的引用。

该句子的意思是有问题的文档将不会包含在索引中,并且可能会从查询结果中丢失

例如:

> db.test.insert({_id: 0, a: "abc"})

> db.test.insert({_id: 1, a: "def"})

> db.test.insert({_id: 2, a: <string more than 1024 characters long>})

> db.adminCommand( { setParameter: 1, failIndexKeyTooLong: false } )

> db.test.find()
{"_id": 0, "a": "abc"}
{"_id": 1, "a": "def"}
{"_id": 2, "a": <string more than 1024 characters long>}
Fetched 3 record(s) in 2ms

> db.test.find({a: {$ne: "abc"}})
{"_id": 1, "a": "def"}
Fetched 1 record(s) in 1ms
Run Code Online (Sandbox Code Playgroud)

通过强制MongoDB忽略该failIndexKeyTooLong错误,最后一个查询不包含有问题的文档(即_id: 2,结果中缺少的文档),因此该查询导致了错误的结果集。


小智 6

当遇到“索引键限制”时,解决方案取决于您的架构的需求。在极少数情况下,设计要求对大于 1024 字节的值进行密钥匹配。事实上,几乎所有数据库都施加了索引键限制,但通常在传统关系数据库(Oracle/MySQL/PostgreSQL)中可以进行一定程度的配置,因此您很容易搬起石头砸自己的脚。

为了快速搜索,“文本”索引旨在优化长文本字段的搜索和模式匹配,并且非常适合该用例。然而,更常见的是,需要对长文本值进行唯一性约束。并且“文本”索引的行为与具有唯一标志集的唯一标量值不同 { unique: true }(更像是字段中所有文本字符串的数组)。

受到 MongoDb 的 GridFS 的启发,通过向文档添加“md5”字段并在其上创建唯一的标量索引,可以轻松实现唯一性检查。有点像自定义的唯一哈希索引。这允许几乎无限的(〜16mb)文本字段长度,该长度被索引以供搜索并且在整个集合中是唯一的。

const md5 = require('md5');
const mongoose = require('mongoose');

let Schema = new mongoose.Schema({
  text: {
    type: String,
    required: true,
    trim: true,
    set: function(v) {
        this.md5 = md5(v);
        return v;
    }
  },
  md5: {
    type: String,
    required: true,
    trim: true
  }
});

Schema.index({ md5: 1 }, { unique: true });
Schema.index({ text: "text" }, { background: true });
Run Code Online (Sandbox Code Playgroud)