在Mongodb上使用带地理空间索引的全文搜索

在Mongodb上使用带地理空间索引的全文搜索,mongodb,full-text-search,mongodb-query,geospatial,Mongodb,Full Text Search,Mongodb Query,Geospatial,比如说,我想开发一个android应用程序,允许用户搜索离你最近的酒店。这在当今的应用程序中非常常见,例如AirBnb 这是我正在使用的数据集: { "name" : "The Most Amazing Hotel", "city" : "India", "type": "Point" "coord": [ -56.16082, 61.15392 ] } { "name" : "The Most Incredi

比如说,我想开发一个android应用程序,允许用户搜索离你最近的酒店。这在当今的应用程序中非常常见,例如AirBnb

这是我正在使用的数据集:

{
    "name" : "The Most Amazing Hotel",
    "city" : "India",
    "type": "Point"
    "coord": [
        -56.16082,
        61.15392
      ]
}

{
    "name" : "The Most Incredible Hotel",
    "city" : "India",
    "type": "Point"
    "coord": [
        -56.56285,
        61.34590
      ]
}

{
    "name" : "The Fantastic GuestHouse",
    "city" : "India",
    "type": "Point"
    "coord": [
        -56.47085,
        61.11357
      ]
}
现在,我想在
名称
字段上创建一个文本索引,以便它按名称搜索,然后根据坐标按地理空间索引排序

因此,如果我搜索“最多”一词,它将按名称搜索“最多”一词,并返回最近的酒店,其中包含“最多”一词

mongodb甚至支持这种类型的搜索吗

我在这里阅读mongodb指南:

复合文本索引不能包含任何其他特殊索引类型, 例如多键或地理空间索引字段


据我所知,我并没有创建复合文本索引。这是一个简单的文本索引,这意味着我只为
名称
字段而不是
城市
名称
字段编制文本索引。

有一种公平的情况,你根本不需要这个,因为很难证明这样一个索引的用例是合理的我认为“搜索酒店”并不是“文本”和“地理空间”搜索的结合

事实上,“大多数人”会寻找接近某个地点的东西,或者更可能接近他们想去的不同地点,作为他们主要标准的一部分,然后其他“赢家”可能会更重视“成本”、“评级”、“品牌”、“设施”,甚至可能更接近餐馆等

将“文本搜索”添加到该列表是一件非常不同的事情,在这个特定的应用程序中可能没有多大实际用途

尽管如此,这可能值得一些解释,这里有一些概念需要理解,至少对于这个用例来说,这两个概念没有真正的“啮合”

固定模式 首先,我想建议稍微“调整”一下您的数据模式:

{
“名称”:“最令人惊叹的酒店”,
“城市”:“印度”,
“地点”:{
“类型”:“点”,
“坐标”:[
72.867804,
19.076033
]
}
}
这至少提供了
“location”
作为有效的GeoJSON对象进行索引,而且您通常希望使用GeoJSON而不是传统的坐标对,因为它确实为查询和存储提供了更多选项,而且距离标准化为米,而不是全球范围内相等的“弧度”

为什么他们不一起工作 因此,您的阅读基本上是正确的,因为您不能同时使用多个特殊索引。首先看一下复合索引定义:

db.hotels.createIndex({“name”:“text”,“location”:“2dsphere”})
{ “ok”:0, “errmsg”:“错误的索引键模式{name:\'text\”,位置:\'2dsphere\”}:不能对单个索引使用多个索引插件。”, “代码”:67}

所以这是不可能的。即使单独考虑:

db.hotels.createIndex({“name”:“text”})
db.hotels.createIndex({“location”:“2dsphere”})
然后尝试执行查询:

db.hotels.find({
“地点”:{
“$nearSphere”:{
“$geometry”:{
“类型”:“点”,
“坐标”:[
72.867804,
19.076033
]
}
}
},
“$text”:{“$search”:“惊人”}
})
错误:命令失败:{ “waitedMS”:数字长(0), “ok”:0, “errmsg”:“不允许在同一查询中使用文本和地理位置”, “代码”:2 }:未定义

这实际上支持了为什么不能用三种方式在复合索引中定义它的原因:

  • 如初始错误所示,MongoDB中处理这些“特殊”索引的方式本质上需要“分支”到所选索引类型的“特殊”处理程序,并且这两个处理程序不在同一个位置

  • 即使使用单独的索引,由于逻辑基本上是一个“and”条件,MongoDB也无法实际选择多个索引,而且由于两个查询子句都需要“特殊”处理,因此实际上需要这样做。而且它不能

  • 即使这在逻辑上是一个
    $或
    条件,您基本上回到点1,在这里,即使应用“索引交集”,这种“特殊”索引也有另一个属性,它们必须在“顶层”应用“以允许选择索引。将它们包装在
    $或
    中意味着MongoDB不能这样做,因此不允许这样做

  • 但你可以“欺骗” 所以每一个基本上都是独占的,你不能同时使用它们。但当然,你总是可以“作弊”,这取决于哪个搜索顺序对你更重要

    通过“位置”首先:

    db.hotels.aggregate([
    {“$geoNear”:{
    “近”:{
    “类型”:“点”,
    “坐标”:[
    72.867804,
    19.076033
    ]
    },
    “球形”:正确,
    “最大距离”:5000,
    “距离字段”:“距离”,
    “查询”:{
    “姓名”:/惊人/
    }
    }}
    ])
    
    甚至:

    db.hotels.find({
    “地点”:{
    “$nearSphere”:{
    “$geometry”:{
    “类型”:“点”,
    “坐标”:[
    72.867804,
    19.076033
    ]
    },
    “$maxDistance”:5000
    }
    },
    “姓名”:/惊人/
    })
    
    或先通过文本搜索:

    db.hotels.find({
    “$text”:{“$search”:“惊人”},
    “地点”:{
    “$GEOIN”:{
    “$centerSphere”:[[
    72.867804,