如何在2d索引中使用MongoDB组合两个索引,日期索引和Geo?

时间:2015-02-19 17:19:44

标签: mongodb indexing mongoid geospatial

我使用Mongoid与mongo交互。如何在一个查询中组合两个索引? created_at上的一个索引和loc.coordinates上的另一个索引可以快速搜索我的数据?理想情况下,我不想进行全表扫描,我注意到我的2d索引,nscannedObjects命中每条记录(69)。

第三个查询应该有效,但失败是因为" planner返回错误:错误提示"

查询1:

@snaps = Snap.where(:created_at=>(2.days.ago..Time.now), :loc => { "$within" => { "$polygon" => hood }}).criteria.extras(:hint => {"created_at"=>-1}).order_by(:created_at => 'desc').limit(50).skip(offset).explain()

Query explain():         

   => {"cursor"=>"BtreeCursor created_at_-1", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>15, "nscanned"=>15, "nscannedObjectsAllPlans"=>15, "nscannedAllPlans"=>15, "scanAndOrder"=>false, "indexOnly"=>false, "nYields"=>0, "nChunkSkips"=>0, "millis"=>0, 
"indexBounds"=>{"created_at"=>[[2015-02-19 17:03:38 UTC, 2015-02-17 17:03:38 UTC]]}, 
"allPlans"=>[{"cursor"=>"BtreeCursor created_at_-1", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>15, "nscanned"=>15, "scanAndOrder"=>false, "indexOnly"=>false, "nChunkSkips"=>0, 
"indexBounds"=>{"created_at"=>[[2015-02-19 17:03:38 UTC, 2015-02-17 17:03:38 UTC]]}}], "server"=>"snapdate:27017", "filterSet"=>false, "stats"=>{"type"=>"LIMIT", "works"=>17, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>12, "needFetch"=>0, "isEOF"=>1, 
"children"=>[{"type"=>"FETCH", "works"=>17, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>12, "needFetch"=>0, "isEOF"=>1, "alreadyHasObj"=>0, "forcedFetches"=>0, "matchTested"=>4, "children"=>[{"type"=>"IXSCAN", "works"=>16, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>15, "needTime"=>1, "needFetch"=>0, "isEOF"=>1, 
"keyPattern"=>"{ created_at: -1.0 }", 
"isMultiKey"=>0, "boundsVerbose"=>"field #0['created_at']: [new Date(1424365418271), 
new Date(1424192618271)]", 
"yieldMovedCursor"=>0, "dupsTested"=>0, "dupsDropped"=>0, "seenInvalidated"=>0, "matchTested"=>0, "keysExamined"=>15, "children"=>[]}]}]}}

查询2:

 @snaps = Snap.where(:created_at=>(2.days.ago..Time.now), :loc => { "$within" => { "$polygon" => hood }}).criteria.extras(:hint => {"loc.coordinates"=>'2d'}).order_by(:created_at => 'desc').limit(50).skip(offset).explain()

查询2解释():

=> {"cursor"=>"BtreeCursor loc.coordinates_2d", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>69, "nscanned"=>69, "nscannedObjectsAllPlans"=>69, "nscannedAllPlans"=>69, "scanAndOrder"=>true, "indexOnly"=>false, "nYields"=>0, "nChunkSkips"=>0, "millis"=>0, "indexBounds"=>{"loc.coordinates"=>[[{"$minElement"=>1}, {"$maxElement"=>1}]]}, "allPlans"=>[{"cursor"=>"BtreeCursor loc.coordinates_2d", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>69, "nscanned"=>69, "scanAndOrder"=>true, "indexOnly"=>false, "nChunkSkips"=>0, "indexBounds"=>{"loc.coordinates"=>[[{"$minElement"=>1}, {"$maxElement"=>1}]]}}], "server"=>"snapdate:27017", "filterSet"=>false, "stats"=>{"type"=>"SORT", "works"=>77, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>71, "needFetch"=>0, "isEOF"=>1, "forcedFetches"=>0, "memUsage"=>2671, "memLimit"=>33554432, "children"=>[{"type"=>"KEEP_MUTATIONS", "works"=>71, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>66, "needFetch"=>0, "isEOF"=>1, "children"=>[{"type"=>"FETCH", "works"=>71, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>66, "needFetch"=>0, "isEOF"=>1, "alreadyHasObj"=>0, "forcedFetches"=>0, "matchTested"=>4, "children"=>[{"type"=>"IXSCAN", "works"=>70, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>69, "needTime"=>1, "needFetch"=>0, "isEOF"=>1, "keyPattern"=>"{ loc.coordinates: \"2d\" }", "isMultiKey"=>0, "boundsVerbose"=>"field #0['loc.coordinates']: [MinKey, MaxKey]", "yieldMovedCursor"=>0, "dupsTested"=>0, "dupsDropped"=>0, "seenInvalidated"=>0, "matchTested"=>0, "keysExamined"=>69, "children"=>[]}]}]}]}}

第三次查询失败:

@snaps = Snap.where(:created_at=>(2.days.ago..Time.now), :loc => { "$within" => { "$polygon" => hood }}).criteria.extras(:hint => {"created_at"=>-1,"loc.coordinates"=>'2d'}).order_by(:created_at => 'desc').limit(50).skip(offset).explain()

第三次查询失败解释()

  @selector={"$query"=>{"created_at"=>{"$gte"=>2015-02-17 17:10:39 UTC, "$lte"=>2015-02-19 17:10:39 UTC}, "loc"=>{"$within"=>{"$polygon"=>[[-122.4310827255249, 37.76572785787643], [-122.4301815032959, 37.75795850991872], [-122.42576122283936, 37.75822994194451], [-122.42477416992188, 37.74781302376846], [-122.42249965667725, 37.748050559413784], [-122.4079942703247, 37.748423828173124], [-122.40408897399902, 37.74950969022236], [-122.40310192108154, 37.751647434568056], [-122.40310192108154, 37.75371725516446], [-122.40344524383545, 37.75673705347827], [-122.40636348724365, 37.75948530210884], [-122.4065351486206, 37.76114777332217], [-122.40559101104736, 37.76297984117803], [-122.40520477294922, 37.7654225277299], [-122.40589141845703, 37.76786513360663], [-122.40812301635742, 37.769357797482144], [-122.41636276245117, 37.769629187677], [-122.42198467254639, 37.77027373539786], [-122.42365837097168, 37.77180027337858], [-122.4310827255249, 37.76572785787643]]}}}, "$explain"=>true, "$orderby"=>{"created_at"=>-1}, "$hint"=>{"created_at"=>-1, "loc.coordinates"=>"2d"}}
  @fields=nil>
failed with error 17007: "Unable to execute query: error processing query: ns=snapdate_production.snaps limit=50 skip=0\nTree: $and\n    created_at $lte new Date(1424365839454)\n    created_at $gte new Date(1424193039454)\n    GEO raw = { loc: { $within: { $polygon: [ [ -122.4310827255249, 37.76572785787643 ], [ -122.4301815032959, 37.75795850991872 ], [ -122.4257612228394, 37.75822994194451 ], [ -122.4247741699219, 37.74781302376846 ], [ -122.4224996566772, 37.74805055941378 ], [ -122.4079942703247, 37.74842382817312 ], [ -122.404088973999, 37.74950969022236 ], [ -122.4031019210815, 37.75164743456806 ], [ -122.4031019210815, 37.75371725516446 ], [ -122.4034452438354, 37.75673705347827 ], [ -122.4063634872437, 37.75948530210884 ], [ -122.4065351486206, 37.76114777332217 ], [ -122.4055910110474, 37.76297984117803 ], [ -122.4052047729492, 37.7654225277299 ], [ -122.405891418457, 37.76786513360663 ], [ -122.4081230163574, 37.76935779748214 ], [ -122.4163627624512, 37.769629187677 ], [ -122.4219846725464, 37.77027373539786 ], [ -122.4236583709717, 37.77180027337858 ], [ -122.4310827255249, 37.76572785787643 ] ] } } }\nSort: { created_at: -1 }\nProj: {}\n planner returned error: bad hint"

我的索引:

 db.snaps.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "snapdate_production.snaps"
    },
    {
        "v" : 1,
        "key" : {
            "loc.coordinates" : "2d"
        },
        "name" : "loc.coordinates_2d",
        "ns" : "snapdate_production.snaps"
    },
    {
        "v" : 1,
        "key" : {
            "created_at" : -1
        },
        "name" : "created_at_-1",
        "ns" : "snapdate_production.snaps"
    }
]

根据评论进行更新

评论:db.snaps.ensureIndex({ "created_at" : 1, "loc.coordinates" : "2d" })

irb(main):009:0> @snaps = Snap.where(:created_at=>(2.days.ago..Time.now), :loc => { "$within" => { "$polygon" => hood }}).criteria.extras(:hint => "loc.coordinates_2d_created_at_-1").order_by(:created_at => 'desc').limit(50).skip(offset).explain()
=> {"cursor"=>"BtreeCursor loc.coordinates_2d_created_at_-1", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>74, "nscanned"=>74, "nscannedObjectsAllPlans"=>74, "nscannedAllPlans"=>74, "scanAndOrder"=>true, "indexOnly"=>false, "nYields"=>0, "nChunkSkips"=>0, "millis"=>1, "indexBounds"=>{"loc.coordinates"=>[[{"$minElement"=>1}, {"$maxElement"=>1}]], "created_at"=>[[{"$maxElement"=>1}, {"$minElement"=>1}]]}, "allPlans"=>[{"cursor"=>"BtreeCursor loc.coordinates_2d_created_at_-1", "isMultiKey"=>false, "n"=>4, "nscannedObjects"=>74, "nscanned"=>74, "scanAndOrder"=>true, "indexOnly"=>false, "nChunkSkips"=>0, "indexBounds"=>{"loc.coordinates"=>[[{"$minElement"=>1}, {"$maxElement"=>1}]], "created_at"=>[[{"$maxElement"=>1}, {"$minElement"=>1}]]}}], "server"=>"snapdate:27017", "filterSet"=>false, "stats"=>{"type"=>"SORT", "works"=>82, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>76, "needFetch"=>0, "isEOF"=>1, "forcedFetches"=>0, "memUsage"=>2793, "memLimit"=>33554432, "children"=>[{"type"=>"KEEP_MUTATIONS", "works"=>76, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>71, "needFetch"=>0, "isEOF"=>1, "children"=>[{"type"=>"FETCH", "works"=>76, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>4, "needTime"=>71, "needFetch"=>0, "isEOF"=>1, "alreadyHasObj"=>0, "forcedFetches"=>0, "matchTested"=>4, "children"=>[{"type"=>"IXSCAN", "works"=>75, "yields"=>0, "unyields"=>0, "invalidates"=>0, "advanced"=>74, "needTime"=>1, "needFetch"=>0, "isEOF"=>1, "keyPattern"=>"{ loc.coordinates: \"2d\", created_at: -1.0 }", "isMultiKey"=>0, "boundsVerbose"=>"field #0['loc.coordinates']: [MinKey, MaxKey], field #1['created_at']: [MaxKey, MinKey]", "yieldMovedCursor"=>0, "dupsTested"=>0, "dupsDropped"=>0, "seenInvalidated"=>0, "matchTested"=>0, "keysExamined"=>74, "children"=>[]}]}]}]}}
irb(main):010:0>

1 个答案:

答案 0 :(得分:0)

Loc.geo_near([la, lo]).where(loc_field: value)  

无法工作,因为geo_near没有返回Mongoid :: Collection对象。另外,正如您所说,搜索地理位置会触及每条记录。

解决方案是首先搜索您的字段,然后搜索您的坐标。

Loc.where(loc_fields: value).geo_near([la, lo])

然后它将首先搜索您的索引字段(更快),最后搜索地理索引。