如何使用Google App Engine Search API查找最近的文档?

时间:2013-03-06 18:19:31

标签: google-app-engine python-2.7 gae-search

我在GAE Search索引中有大约400,000个文档。所有文档都有location GeoPoint属性,遍布全球。有些文件可能距离任何其他文件超过4000公里,其他文件可能在相距数米的范围内聚集。

我想找到最接近特定坐标集的文档,但发现以下代码给出的结果不正确:

from google.appengine.api import search

# coords are in the form of a tuple e.g. (50.123, 1.123)
search.Document(
    doc_id='meaningful-unique-id',
    fields=[search.GeoField(name='location' 
                            value=search.GeoPoint(coords[0], coords[1]))])

# find document function radius is in metres
def find_document(coords, radius=1000000):
    sort_expr = search.SortExpression(
        expression='distance(location, geopoint(%.3f, %.3f))' % coords,
        direction=search.SortExpression.ASCENDING,
        default_value=0)

    search_query = search.Query(
        query_string='distance(location, geopoint(%.3f, %.3f)) < %d' \
                    % (coords[0], coords[1], radius),
        options=search.QueryOptions(
            limit=1,
            ids_only=True,
            sort_options=search.SortOptions(expressions=[sort_expr])))

    index = search.Index(name='document-index')
    return index.search(search_query)

使用此代码,我将获得一致但不正确的结果。例如,搜索距离伦敦最近的文件表明最接近的文件在苏格兰。我已经证实有成千上万的文件。

我将问题缩小到radius参数太大。如果半径下降到大约12km(radius=12000),我得到正确的结果。在12公里半径内通常不超过1000个文件。 (可能与search.SortOptions(limit=1000)相关联。)

问题在于,如果我在地球的稀疏区域,那里没有任何数千英里的文件,我的搜索功能将不会返回radius=12000(12公里)的任何内容。无论我在哪里,我希望它能将最接近的文件归还给我。如何通过调用Search API始终如一地完成此操作?

3 个答案:

答案 0 :(得分:5)

我认为问题如下。 您的查询将选择最多10K个文档,然后根据距离排序表达式对其进行排序并返回。 (也就是说,排序实际上并不是超过所有400k文档。) 所以我怀疑这个10k选择中没有包含一些地理位置较近的点。 这就是为什么当您缩小搜索半径时事情会更好,因为您在该半径中的总点数较少。

基本上,您希望以对您查询的内容有意义的方式将查询“点击”降低到10k。 您可以通过以下几种方式解决这个问题,您可以将它们结合起来:

  • 添加排名,以便按照排名顺序返回最“重要”的文档(根据您的域中有意义的某些条件),然后按距离对这些文档进行排序。
  • 过滤一个或多个文档字段(例如,“业务类别”,如果您的文档包含有关商家的信息),以减少候选文档的数量。

(我不相信这个10k阈值目前在Search API文档中;我已经提交了一张票来添加它。)

答案 1 :(得分:1)

我有完全相同的问题,我认为不可能。问题发生在你自己已经知道什么时候有更多可能的结果而不是返回的结果。 Google算法在加载限制时退出,然后对结果进行排序。

我看到了与您及其搜索API部分相同的群集。

One Hack将您的搜索细分为子扇区,进行多个同时调用,然后合并并对结果进行排序。

答案 2 :(得分:0)

狂野的想法,为什么不保持/记录3点的距离,然后从中计算。