标签:mongo

浏览模式: 标准 | 列表 | 图文
mongodb 的 geo near

mongodb 的 geo near

本来是想用mongo的geo功能来做查询,想着这个功能是它自带的,性能一定很牛叉吧?结果事实让我们非常失望。

我们做了一个简单的测试,插了1000万条数据,y=x的方式插入,即[0.00001,0.00001]~[99.99999,99.99999],在坐标上其实就是显示成一条实现。如果我们随便指定一个坐标值,求near。你会发现其实很卡。。。20多秒才能出数据,而且还不准。

要知道我的机器可是:i7 4核,16G内存,SSD的硬盘,都这么卡,而且出来的都这么慢。

当然,其实更重要的是不准。。。我坐标[20,90],查出来的点,居然是[55,55],这太让人伤心了。随便算了算,怎么着都应该是77左右啊。。。

估计,只能用mysql了。。。伤心。

关于mongo的GEO相关笔记

关于mongo的GEO相关笔记

很乱。我自己明白即可,三种查询条件。

{loc:{"$near":[121.417397,31.204075]} }
{loc : {"$within" : {"$center" : [ [121.417397,31.204075], 5]}} }
db.places.find({loc:{ $near:[ 30.28009,120.12857],$maxDistance:5}}).limit(20)

上述的内容参考与某个网站,它的基本内容如下:

最近一直在做基于LBS的项目,地标的坐标索引和基于坐标查询,一直没找到一种简单方便的方法,在做mongo索引优化的时发现竟然有Geo的索引
创建字段
建议使用方式:{ loc : [ longitude , latitude] }
也可以:{ loc : { lon :longitude, lat:latitude } }
Loc自己决定,我用poi的
建立索引
注意:每个Collection只能建立一个geospatial索引
db.places.ensureIndex( { loc : “2d” } , { min : -500 , max : 500 } )
如果db.places.ensureIndex( { loc : “2d” }),
默认值的范围是:-180到180,也就是经纬度的范围
查询
注:1.默认会按距离排序;
2.转换 111.12 距离(一度是大约 111.12 公里)使用公里,或由 69 (对于英里)
默认取100条距离最近的点,注:默认是limit(100)
db.collection.find({loc:{$near :[ 30.28009,120.12857]}})
取正方形范围的坐标点,注意:5是坐标系的5,也就是经纬度的5,按111.12换算成公里
db.places.find({loc:{ $near:[ 30.28009,120.12857],$maxDistance:5}}).limit(20)
取指定半径的点,注意:半径5是坐标系的5,也就是经纬度的5,按111.12换算成公里
以5为半径的圆:{“Coordinate” : {“$within” : {“$center” : [ [30.28009,120.12857], 5]}} }
---------

纯笔记,别多想,测试了一下。比现在使用的好多了,我现在是:
$criteria->order = new \CDbExpression("ACOS(SIN(({$lat} * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS(({$lat} * 3.1415) / 180 ) * COS((lat * 3.1415) / 180 ) *COS(({$lng} * 3.1415) / 180 - (lng * 3.1415) / 180 ) ) * 6380 asc,last_activity_time DESC");

不要多想,我是用的Yii的玩意,也是一个笔记。

mongo中的group by

mongo中的group by

在mysql里面,我们偶尔会有这样的sql出现:
select userid,count(userid) as cnt from xxxxxtable group by userid;

这样的sql在mongo里怎么实现呢?其实也相对比较简单

<?php
$mongo = new Mongo();
$mongo->selectDB('xxx');//库
$collection = $mongo->selectCollection('表');

$field = array('userid'=>1);
$cnt = array('cnt'=>0);
$result = $collection->group($field,$cnt,"function(obj,pref){pref.cnt++;}");

打印出来的结果也很方便识别:

Array
(
[retval] => Array
(
[0] => Array
(
[userid] => 11111
[cnt] => 2
)
//省略
)

[count] => 21
[keys] => 11
[ok] => 1
)

果然轻轻松松啊

为列表提速

为列表提速

这是一段时间的我的经历和笔记,看过之前的博客的人应该会看到,我在用mongo,是的,我将大量的数据用mongo存储了,但最终我还是放弃了。理由有很多,不过我还是慢慢列出来吧
1、为什么用mongo
因为当初设计数据库的时候仓促,本来认为只有2~30万的数据,但最终却发现会有200多万条,以后可能还会更加多,所以当初很多大字段都扔在了一个表里,导致如果用in查询,非常慢。所以我想用mongo,扔到内存里查询,看看效果是否会很好。

2、为什么又放弃使用mongo了
说实话,mongo在做关系查询的方面确实挺不错,但存在的问题是我的数据都是用php往mongo里导入,而mongo对于数字和字符串还是认得比较严 的。当然这都不是问题。。问题是现在没有专门的DBA,以后对数据不太容易,也不太方便管理。毕竟目前公司的整体项目,大部分都是用mysql在做处理, 所以,为了配合更多人,才放弃使用mongo(当然,也是为了节约内存)

3、mongo在使用时的优缺点
其实mongo在仅做处理这些条件查询的时候,并没有想象中的那样。当然确实很快,不过在第一次查询的时候还是有点慢的,然后在数据没有变化的时候查询数 据都在0.00x秒,不过,我真的没有太在意(其实有点在意,但因为那个条件也是用mysql生成出来的,再加上查询之前对于那些字段都得做一次强制转 换,否则对于查询的时候可能就出不来数据)

4、最终我怎么做了
既然我已经知道我原来的数据表的问题在哪里,我就想办法处理掉不就完了?于是写了一个脚本,自己将主表的数据中的几个重要的,用来查询和排序的字段拎出来,重建一个表,用来查询,将可变字段改成定长字段,为了提速。这样一来,速度比原来最少快了两个等级。

5、下一步我会怎么做
其实现在做很多事情都是偷懒了,比如对于字段是int型的时候,却还是用的where id = '1',而不是where id = 1;
所以这是后期考虑优化的地方。
当然因为将主要字段分拆成表,所以带来的另一个问题是,当更改原表的时候,需要对新表做更新处理。

6、最后说一下
原表的索引,原来达到了300多M,后来因为把数据迁到新表(做冗余),在新的表建的索引,只有70多M,而且原表因为将索引清除了,编辑和插入的数据又上了一个等级,最终还是觉得这样有优势 。

---PS
不一定要学我,我这也是自己的经历,没有什么可比和可参照性。当然你要骂我那是可以的

Mongodb 中字段类型的郁闷

Mongodb 中字段类型的郁闷

之前在“ Yii的又一个BUG?”提过我将数据导入到数据库时,进直接用ActiveRecord导入的,所以字段的类型都是String,后来发现问题,指定字段 为int值
这两天为了做一个查询,看了一下程序又遇到了问题:
同样的参数,同样的内容,一个查询能够有值,一个查询一点数据都没有。。。这是怎么回事?
一步步的测试下来,最后怀疑是字段类型,从$_GET回来的参数应该是字符串型而不是int,于是做了一个强制转换,数据果然就有了。我晕啊。。。大哥,你绕了我吧?
看来以后对于这类的数据,只要涉及mongo的,还是要多做一次额外的处理,否则连问题都没法发现。当然这也是因为不细心导致的。
慎记

mongodb删除索引

mongodb删除索引

在讲今天的内容前,请允许我说几句:what the fuck,再说一句:“你哭著對我說童話裡都是騙人的”
前两天说过为了速度我建了索引,虽然给id建了unique的索引,但是数据还是不由分说的插了重复的。好吧。因为数据在unique前就进数据库了。所以。。。我必须要再加上dropDups这个条件。

于是乎,我就先开始删除索引,然后灾难就来了:

b.archive.dropIndex({id:1,unique:true})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({"id":1,"unique":true})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({"id":1,"unique":true},{name:"id"})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({"id":1,"unique":true},{"name":"id"})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({category_id:1})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({"category_id":1})
{ "errmsg" : "index not found", "ok" : 0 }
> db.archive.dropIndex({"key":{"status":1}})
{ "errmsg" : "index not found", "ok" : 0 }

为什么为什么????
为什么我会这么做?是因为:http://www.mongodb.org/display/DOCS/Indexes
这里面写着:

Dropping Indexes

To delete all indexes on the specified collection:

db.collection.dropIndexes();

To delete a single index:

db.collection.dropIndex({x: 1, y: -1})

Running directly as a command without helper:

// note: command was "deleteIndexes", not "dropIndexes", before MongoDB v1.3.2 // remove index with key pattern {y:1} from collection foo db.runCommand({dropIndexes:'foo', index : {y:1}}) // remove all indexes: db.runCommand({dropIndexes:'foo', index : '*'})

我晕啊。这是肿么了。。。
后来还是神仙和赵拂衣说了一句,试一下dropIndex("xxx"),果然。。。Over了。你说,你这不是忽悠人嘛 ,为了这个,我折腾了一个晚上啊。。。。
害得我当时只能dropIndexes,先删除所有的,再重建索引。。。数据又多,我等了好久好久啊。

mongodb用索引与不用索引的区别(续)

mongodb用索引与不用索引的区别(续)

前段时候做了个一万条数据的对比,这回做了个2000000条数据的对比:
测试方式还是和以前一样:

测试开始:
1、order by id ASC limit 25,很常见的查询吧。每页显示25条。
没有索引的时候:0.05秒左右(1万条是0.88秒,很奇怪)
用了id,unique索引后,0.004,第一次的时候0.08,后面稳定在0.00x左右(与1W左右一致)

2、where category_id = 1 limit 25,某个条件
无索引时:24秒左右 (很夸张。。。)
有索引:第一次0.06左右,后面稳定在0.00x(x>6),即在0.006~0.01之间(与1W左右一致)

3、where category_id = xx order by pubdate limit 25
无索引:20秒左右,最慢的一次达到了70秒
有索引的时候,与条件2差不多。。

虽然不是特别的深入测试,但这样也几乎足够了。不过,这带来另一个问题。内存消耗比较大啊。果然是吃内存大户

mongodb用索引与不用索引的区别

mongodb用索引与不用索引的区别

因为我mongo也是刚刚开始用,所以有一些地方的测试就不如很多专业人士了,但不代表我不能发言啊。。。

测试数据,11000左右,全部是int型字段(关于int型和字符串型,之前讲过了)
11000条,占用空间并不大,关键是看速度。。
11000条的数据的字段:id,pubdate,category_id,status,is_top,为什么只有这些字段 ?因为详细字段的Cache已经由redis实现,而redis不支持条件查询,所以将这些条件查询用mongo来代替了。你懂的。。为了速度。。。

测试开始:
1、order by id ASC limit 25,很常见的查询吧。每页显示25条。
没有索引的时候:0.88秒左右
用了id,unique索引后,0.004,第一次的时候0.08,后面稳定在0.00x左右

2、where category_id = 1 limit 25,某个条件
无索引时:0.6秒左右
有索引:第一次0.06左右,后面稳定在0.00x(x>6),即在0.006~0.01之间

3、where category_id = xx order by pubdate limit 25
无索引:0.8,最慢的一次达到了1.5秒
有索引的时候,与条件2差不多

至此第一步测试完毕,下一步测试200万左右数据。。还没有开始。因为都是真实数据,插起来比较麻烦

NND被mongodb的limit BUG搞死了

NND被mongodb的limit BUG搞死了

昨天下载了php-mongo的组件进行了安装。结果在进行limit查询的时候一直reset。。查了半天,以为是语法错误 ,但最终都没有发现任何问题。当时我下的包是:https://nodeload.github.com/mongodb/mongo-php-driver/tarball/master,嗯。这是一个最新版。文件名是:mongodb-mongo-php-driver-1.3.0beta1-15-ge426381.tar.gz,一眼就可以看出这是一个beta版。我晶。。。就因为它,害得我折腾了一个晚上

各位看官:

$mongo = new Mongo();
$db = $mongo->selectCollection('orange','archive');
$query = $db->find(array("pubdate"=>array('$gt'=>'100000000'),'status'=>array('$in'=>array('0','9'))))->limit(10);
foreach ($query as $q) {
echo "<pre>";
print_r($q);
echo "</pre>";
}

这两句没问题吧。。。但事实上在1.3中就会导致 直接reset。如果不加limit条件就一切正常。我算是。。。蛋疼了。

后来从pecl.php.net中搜索mongo,网址其实就是在:http://pecl.php.net/package/mongo,然后下载了1.2.12:http://pecl.php.net/get/mongo-1.2.12.tgz,下载完后重新编译,又是那两句简单的代码:
phpize
./configure
make install
然后重启。。。一切就太平了。

SQL to Mongo Mapping Chart

SQL to Mongo Mapping Chart

mysql 与 mongo之间是怎么替换的?
官方有一个表格:

SQL Statement Mongo Query Language Statement
CREATE TABLE USERS (a Number, b Number) Implicit or use MongoDB::createCollection().
INSERT INTO USERS VALUES(1,1) $db->users->insert(array("a" => 1, "b" => 1));
SELECT a,b FROM users $db->users->find(array(), array("a" => 1, "b" => 1));
SELECT * FROM users WHERE age=33 $db->users->find(array("age" => 33));
SELECT a,b FROM users WHERE age=33 $db->users->find(array("age" => 33), array("a" => 1, "b" => 1));
SELECT a,b FROM users WHERE age=33 ORDER BY name $db->users->find(array("age" => 33), array("a" => 1, "b" => 1))->sort(array("name" => 1));
SELECT * FROM users WHERE age>33 $db->users->find(array("age" => array('$gt' => 33)));
SELECT * FROM users WHERE age<33 $db->users->find(array("age" => array('$lt' => 33)));
SELECT * FROM users WHERE name LIKE "%Joe%" $db->users->find(array("name" => new MongoRegex("/Joe/")));
SELECT * FROM users WHERE name LIKE "Joe%" $db->users->find(array("name" => new MongoRegex("/^Joe/")));
SELECT * FROM users WHERE age>33 AND age<=40 $db->users->find(array("age" => array('$gt' => 33, '$lte' => 40)));
SELECT * FROM users ORDER BY name DESC $db->users->find()->sort(array("name" => -1));
CREATE INDEX myindexname ON users(name) $db->users->ensureIndex(array("name" => 1));
CREATE INDEX myindexname ON users(name,ts DESC) $db->users->ensureIndex(array("name" => 1, "ts" => -1));
SELECT * FROM users WHERE a=1 and b='q' $db->users->find(array("a" => 1, "b" => "q"));
SELECT * FROM users LIMIT 10 SKIP 20 $db->users->find()->limit(10)->skip(20);
SELECT * FROM users WHERE a=1 or b=2 $db->users->find(array('$or' => array(array("a" => 1), array("b" => 2))));
SELECT * FROM users LIMIT 1 $db->users->find()->limit(1);
EXPLAIN SELECT * FROM users WHERE z=3 $db->users->find(array("z" => 3))->explain()
SELECT DISTINCT last_name FROM users $db->command(array("distinct" => "users", "key" => "last_name"));
SELECT COUNT(*y) FROM users $db->users->count();
SELECT COUNT(*y) FROM users where AGE > 30 $db->users->find(array("age" => array('$gt' => 30)))->count();
SELECT COUNT(AGE) from users $db->users->find(array("age" => array('$exists' => true)))->count();
UPDATE users SET a=1 WHERE b='q' $db->users->update(array("b" => "q"), array('$set' => array("a" => 1)));
UPDATE users SET a=a+2 WHERE b='q' $db->users->update(array("b" => "q"), array('$inc' => array("a" => 2)));
DELETE FROM users WHERE z="abc" $db->users->remove(array("z" => "abc"));


不过,硬要说的话,这个还不全,http://www.mongodb.org/display/DOCS/SQL+to+Mongo+Mapping+Chart,这里有更全的。
在上面的页面还能够讲这个mapping chart导出成pdf。
比如,这个:d298d1a5bbe9a7784c0027f6def7971e