gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 01:12:11 26 4
gpt4 key购买 nike

假设我想开发一个 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
]
}

现在,我想创建一个 文本索引name字段,以便它按名称搜索,然后根据坐标按地理空间索引排序。

因此,如果我搜索“The Most”这个词,它会按名称搜索“The Most”这个词,并返回最近的带有“The Most in them”的酒店。

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

我正在阅读 mongodb 的指南: https://docs.mongodb.org/manual/core/index-text/

A compound text index cannot include any other special index types, such as multi-key or geospatial index fields.



据我了解,我没有创建复合文本索引。这是一个简单的文本索引,这意味着我只为 name 索引文本。字段而不是 cityname领域。

最佳答案

有一个合理的例子,你真的根本不需要这个,因为很难证明这样一个操作的用例是合理的,我认为“搜索酒店”不是“文本”的组合”和“geoSpatial”搜索确实适用。

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

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

尽管如此,这可能值得一些解释,这里有几个概念需要理解,为什么这两个概念至少在这个用例中没有真正“啮合”。

修复架构

首先,我想提出一个建议来“调整”你的数据模式:

{
"name" : "The Most Amazing Hotel",
"city" : "India",
"location": {
"type": "Point",
"coordinates": [
72.867804,
19.076033
]
}
}

那至少证明 "location"作为用于索引的有效 GeoJSON 对象,您通常需要 GeoJSON 而不是传统的坐标对,因为它确实为查询和存储提供了更多选项,而且距离被标准化为米,而不是等价的“弧度”。地球。

为什么他们不一起工作

所以你的阅读基本上是正确的,因为你不能一次使用多个特殊索引。先看复合索引定义:

db.hotels.createIndex({ "name": "text", "location": "2dsphere" })

{ "ok" : 0, "errmsg" : "bad index key pattern { name: \"text\", location: \"2dsphere\" }: Can't use more than one index plugin for a single index.", "code" : 67 }



所以这是做不到的。甚至单独考虑:

db.hotels.createIndex({ "name": "text" })
db.hotels.createIndex({ "location": "2dsphere" })

然后尝试做一个查询:

db.hotels.find({
"location": {
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [
72.867804,
19.076033
]
}
}
},
"$text": { "$search": "Amazing" }
})

Error: command failed: { "waitedMS" : NumberLong(0), "ok" : 0, "errmsg" : "text and geoNear not allowed in same query", "code" : 2 } : undefined



这实际上以三种方式支持无法在复合索引中定义的原因:
  • 正如最初的错误所表明的那样,在 MongoDB 中处理这些“特殊”索引的方式本质上需要“分支”到所选索引类型的“特殊”处理程序,并且这两个处理程序不在同一个地方。
  • 即使使用单独的索引,由于逻辑基本上是“与”条件,因此 MongoDB 无论如何都不能实际选择多个索引,并且由于两个查询子句都需要“特殊”处理,因此实际上需要这样做。它不能。
  • 即使这在逻辑上是 $or条件,你基本上回到点 1,即使应用“索引交叉”,也有这种“特殊”索引的另一个属性,它们 必须应用于查询操作的“顶级”以允许索引选择。将这些包装在 $or 中意味着 MongoDB 不能这样做,因此是不允许的。

  • 但你可以“作弊”

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

    首先通过“位置”:

    db.hotels.aggregate([
    { "$geoNear": {
    "near": {
    "type": "Point",
    "coordinates": [
    72.867804,
    19.076033
    ]
    },
    "spherical": true,
    "maxDistance": 5000,
    "distanceField": "distance",
    "query": {
    "name": /Amazing/
    }
    }}
    ])

    甚至:

    db.hotels.find({
    "location": {
    "$nearSphere": {
    "$geometry": {
    "type": "Point",
    "coordinates": [
    72.867804,
    19.076033
    ]
    },
    "$maxDistance": 5000
    }
    },
    "name": /Amazing/
    })

    或者先通过文本搜索:

    db.hotels.find({
    "$text": { "$search": "Amazing" },
    "location": {
    "$geoWithin": {
    "$centerSphere": [[
    72.867804,
    19.076033
    ], 5000 ]
    }
    }
    })

    现在,您可以使用 .explain() 仔细查看每种方法中的选择选项。看看发生了什么,但基本情况是每个都只选择一个特殊的索引来分别使用。

    在第一种情况下,它将是用于主要集合的 geoSpatial 索引,它将根据它们与首先给定的位置的接近程度来查找结果,然后通过为 name 给出的正则表达式参数进行过滤。 field 。

    在第二种情况下,它将使用“文本”索引进行主要选择(因此首先找到“惊人”的东西)并从这些结果中应用带有 $geoWithin 的地理空间过滤器(不使用索引) ,在这种情况下,它执行的操作基本上等同于 $near正在做,通过在 circle around a point 中搜索在提供的距离内过滤结果。

    并非“所有”查询都相等

    但要考虑的关键是每种方法很可能返回不同的结果。通过首先缩小位置范围,唯一可以检查的数据是指定距离内的那些位置,因此附加过滤器永远不会考虑距离外的任何“惊人”。

    在第二种情况下,由于文本词是主要搜索,那么 全部 考虑到“Amazing”的结果, 只有二级过滤器可以返回的项目是那些允许从初始文本过滤器返回的项目。

    这在总体考虑中非常重要,因为两个查询操作(“text”和“geoSpatial”)力求实现非常不同的目标。在“文本”情况下,它正在寻找给定术语的“最佳结果”,并且本质上只会返回有限数量的与该术语按排名顺序匹配的结果。这意味着在应用任何其他过滤条件时,满足第一个条件的许多项目很可能不满足附加条件。

    简而言之,“并非所有“令人惊奇”的东西都必须在查询点附近的任何地方”,这意味着具有现实限制,例如 100 results ,并且通过最佳匹配,这 100 个很可能不包含所有“附近”项目。

    另外, $text运算符实际上并没有真正以任何方式对结果进行“排序”。它的主要目的实际上不仅是“匹配”一个短语,而且是 "score"结果是为了将“最佳”匹配 float 到顶部。这通常是在查询本身“之后”完成的,预计值被“排序”并且很可能是“有限”的,如上所述。在聚合管道中可能会这样做,然后应用第二个过滤器,但如上所述,这可能会排除在其他目的中“接近”的事物。

    反过来也可能是正确的(“离该点更远的地方有很多“惊人”的东西”),但在现实的距离限制下,这种情况变得不太可能。但另一个考虑是这不是真正的文本搜索,而只是使用正则表达式来匹配给定的术语。

    最后一点,我总是使用 "Amazing"作为此处的示例短语而不是 "Most"正如问题中所建议的那样。这是因为“词干”在此处(以及大多数专用文本搜索产品)中的文本索引中是如何工作的,因为特定术语将是 忽略 ,就像“and”、“or”、“the”,甚至“in”一样,因为它们对于短语并不真正有值(value),而这正是文本搜索所做的。

    所以事实上,正则表达式实际上会更好地匹配这些术语,如果确实需要的话。

    总结

    这确实让我们回到了原点,因为无论如何“文本”查询确实不属于这里。其他有用的过滤器通常与真正的“geoSpatial”搜索条件配合使用效果会更好,而真正的“文本搜索”在重要内容列表中的位置非常低。

    更有可能的是,人们想要一个位置在距离他们希望访问的期望目的地的*“设置交叉点”之内,或者至少足够接近某些或大多数。当然,前面提到的其他因素(*“价格”、“服务”等)是人们普遍想要的。

    以这种方式寻找结果并不是真正的“合适人选”。如果您认为确实必须,则应用其中一种“作弊”方法,或者实际上使用不同的查询,然后使用其他一些逻辑来合并每组结果。但是服务器单独做这件事确实没有意义,这就是它不尝试的原因。

    所以我会首先专注于让您的地理空间匹配正确,然后应用其他对结果很重要的标准。但我真的不相信“文本搜索”真的可以成为其中之一。而是“作弊”,但前提是您确实必须这样做。

    关于mongodb - 在 Mongodb 上使用带有地理空间索引的全文搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33765288/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com