本片文章,主要去了解一下mongoDB中一些相对特殊的索引。使用面没那么广,适用于特定场合下,比如类队列数据的固定集合、TTL索引、简单字符串搜索的全文本索引等,这种情形下,会有对应的特殊索引.
1. mongoDB中固定集合
-
固定集合的特点和创建方式
mongodb中 普通集合是可以动态创建的,可以自增长。此外,mongodb中也有 一种固定大小的集合,叫固定集合-
在创建的时候,指定大小,
-
类似循环队列 (环形),当数据满了,再插入时,会把最开始的document删除
mongodb这种特性,适用于任何想要自动淘汰过期数据的集合,比如 日志记录、监控记录、行车记录、通话记录等 -
创建语句
基本语法:db.createCollection("集合名词",{capped:true,size:1000,max:100});
参数 :
- capped : true 表示该集合为固定集合
- size : 指定集合大小,单位为KB
- max : 指定文档的数量
db.createCollection("logsQueue",{capped:true,size:100000,max:100}); for(var i=0;i<100;i++){ db.logsQueue.insert({count: i}); }; // 先插入99条数据 db.logsQueue.find()
-
替换旧document示例
上边创建了一个固定集合,并且插入了99条数据,之后,再插入一条数据,发现最开始的第一条数据已经被删除了,测试过程如下> db.logsQueue.find() // .... 第一条数据是 {count : 0} > db.logsQueue.insert({t:1}) > db.logsQueue.find() // .... 第一条数据是{ count : 1 }发现{count : 0}这条记录已经被删除了
- 注意
- 创建固定集合时,限制了集合的大小(size)、集合的文档数量(max), 无论是 先到了size限制,还是先到了文档数量限制,都会将旧文档删除,插入新文档
- 固定集合的结构决定了固定集合不可以分片
-
-
固定集合的自然排序
对固定集合来说,可以进行一种特殊排序,成为自然排序,不同于普通的集合,固定集合是文档是按照插入顺序保存的, 因此它可以按照从旧到新、或者从新到旧排序,如下db.fixCollection.find().sort({"$natural":-1})
2 . TTL索引
- 和固定集合比较
对于固定集合做一个类比, 固定集合如果文档不满是不会被替代的,而TTL索引就可以更加灵活的 老化移除(age-out),
TTL全称是 ”time-to-live index“ : 具有生命周期的索引 , 创建的语法如下
上边的索引意思是 : 当服务器时间比文档的lastUpdated字段晚expireAfterSecs的值,文档就会删除。db.peo.ensureIndex({lastUpdated:1},{"expireAfterSecs":60*60*24})
mongoDB每分钟对TTL索引,进行一次清理, 换句话说,不应该依赖以秒为单位的时间保证索引存活状态
3. 全文本索引
-
创建全文本索引开销
创建任何一种索引,都会需要很高的开销,尤其是经常修改的集合。创建全文本索引的时候,要特别小心,内存可能会不够
全文本索引,可能会导致更严重性能问题,因为它会把所有字符串分解、分词、并且保存到一些地方。因此,拥有全文本索引的集合的写入会比其他集合要差 -
不同版本的创建方式不同
第一次使用全文索引时,没注意到使用的mongodb版本和资料不同,因此一直没有创建成功,后来发现,对于mongodb来说:
在 2.6 版本以后是默认开启全文检索的;
2.6版本之前,可以用如下的命令>db.adminCommand({setParameter:true,textSearchEnabled:true}) // 一定注意,这条命令是2.6之前的,2.6之后的默认开启,无需调用
好的,那我们直接测试全文本索引 ,如下创建数据格式,创建对应的全文本索引
db.peo.insertOne({"post_text":"enjoy the mongodb articles on Runoob","tags":["mongodb","runoob"]}) //创建全文本索引 db.peo.ensureIndex({post_text:"text"})
接下来搜索一下, 看是否可以根据文本查询到这条记录
//搜索文本 > db.peo.find({$text:{$search:"runoob"}}) { "_id" : ObjectId("5d8da6cbfa4e34df34f24b3a"), "post_text" : "enjoy the mongodb articles on Runoob", "tags" : [ "mongodb", "runoob" ] }
不过,当我查询the的时候,发现查询不到,其他的词语都可以
//搜索文本 > db.peo.find({$text:{$search:"articles"}}) { "_id" : ObjectId("5d8da6cbfa4e34df34f24b3a"), "post_text" : "enjoy the mongodb articles on Runoob", "tags" : [ "mongodb", "runoob" ] } > db.peo.find({$text:{$search:"the"}}) //the作为关键字,发现查询不到
后来查询资料,部分说 ”the”在英语分词里被当做stop words处理了,根本不会写入索引,更不会参与查询的 。 这里需要注意一下
-
全文本索引一些细节
资料上说,mongodb用的是开源的snowball分词器 , 这个分词器是支持很多语言的,默认支持英语 , 对汉语支持不是很好。接下来,测试一下汉语的支持程度> db.test1.insertMany([{name:'中国'},{name:'中国 你好'},{name:'你好,中国'},{name:'五千年中国文化'}]) > db.test1.ensureIndex({name:"text"}) > db.test1.find({$text:{$search:" 中国 "}}) { "_id" : ObjectId("5d8dac76fa4e34df34f24b3f"), "name" : "中国" } { "_id" : ObjectId("5d8dac76fa4e34df34f24b41"), "name" : "你好,中国" } { "_id" : ObjectId("5d8dac76fa4e34df34f24b40"), "name" : "中国 你好" } > db.test1.find() { "_id" : ObjectId("5d8dac76fa4e34df34f24b3f"), "name" : "中国" } { "_id" : ObjectId("5d8dac76fa4e34df34f24b40"), "name" : "中国 你好" } { "_id" : ObjectId("5d8dac76fa4e34df34f24b41"), "name" : "你好,中国" } { "_id" : ObjectId("5d8dac76fa4e34df34f24b42"), "name" : "五千年中国文化" } >
很显然,中文是可以用的,不过,看结果来说,如果一句话没有分隔符的话,估计是不会给拆开,因为汉语和英语不同的地方就是,英语单词之间肯定是用空格,但是汉语… 仁者见仁智者见智吧
-
总结一下全文索引的特点
创建语法 :db.collectionName.ensureIndex({attributeName:"text"}) //collectionName : 集合名称 ; attributeName : document中字段名称
查询语法
db.collectionName.find("$text":{"$search":str}) //str : 要查询的字符串
4. 一些更专业性的索引
专业性,换句话说,就是冷门,适用于专门的场景下,博主在实际开发中几乎没用到,也没啥印象,如果不是看mongodb权威指南,估计都不知道,惭愧惭愧
-
先说一下,地理空间
mongodb支持多种地理空间索引,常用的是2dsphere。 2dsphre允许使用GeoJSON格式指定点、线、多边形, 格式如下// loc字段名是任意的,但是它的子对象是GeoJSON指定,不可改变 //点 : [精度、纬度 {"name":"new york", "loc":{ "type":"Point", "coordinates":[50,2] } } //线 由点组成 , 大于等于两个点,表示 {"name":"Hudson River", "loc":{ "type":"Line", "coordinates":[[0,2],[0.1],[1.2]] } } //多边形 和线写法类似,只是type写法不一样 {"name":"Hudson River", "loc":{ "type":"Polygon", "coordinates":[[0,2],[0.1],[1.2]] } }
-
2dsphree如何创建地理空间索引,如何进行查询
db.word.ensureIndex({"loc":"2dsphere"})
地理空间查询,基本用法如下
查询的时候,需要将希望查询的内容指定为形如{"$geometry":geoJsonDesc},
组合上“$geoIntersects” (交集 )、“$within” (包含 )、“$near” (附近 )//比如一个地区 var eastVillage = {"type":"Polygon", "coordinates":[[-73.9917900,40.7264100],[-73.9917900,40.7321400], [-73.9829300,40.7321400]]}
比如查找 和上边代码相近的地方
//有交集 {"$geoIntersects":{"$geometry":eastVillage}} //完全包含 {"$within":{"$geometry":eastVillage}} //附近的 {"$near":{"$geometry":eastVillage}}
而2dsphere 是对点进行索引,可以保存一个由点组成的数组,不会被当做线
5. GridFS : MongoDB中存储大文件
-
GridFS
是MongoDB中一种存储机制,用于存储大型二进制文件。优点很多,比如自动平衡已有的复制或者为MongoDB设置的自动分片,;在用户上传文件时,剞劂一些文件系统可能会遇到问题;存储数据比较大 -
使用
可以使用mongofiles工具,基本操作有三个 put、 list、get 。
可以在shell中或者一些驱动程序中使用,shell中使用如下,一些驱动程序中,用法类似,具体细节可以参考对应驱动的文档> mongofiles put foo.txt > mongofiles list > mongofiles get foo.txt
-
存储格式
GridFS是一种轻量级文件存储规范,存储MongoDB中普通文档,需要注意的是基本上所有的处理都在客户端,由驱动程序和工具负责,服务器端几乎不需处理
基本思路是 : 把大文档拆分成单独存储的小文档,然后加一个文档存储各个小文档的信息,数据格式大体如下{ _id : 文档自带id, n :块在文件中相对位置,比如0或者1或者2... data : 块中包含的二进制数据 files_id : 块所属文件原信息 }