2013-03-06 52 views
6

我在GAE Search索引中有约400,000个文档。所有文件都有一个locationGeoPoint财产,并分布在整个地球。有些文件可能距离任何其他文件超过4000公里,其他文件可能在彼此的米之内。如何使用Google App Engine搜索API找到最接近的文档?

我想找到最接近的文件一组特定的坐标,但发现下面的代码会产生不正确的结果:

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参数太大。如果半径下降到12公里左右(radius=12000),我会得到正确的结果。在12公里范围内通常不会有超过1000个文件。 (可能与search.SortOptions(limit=1000)有关。)

的问题是,如果我在地球上的某个区域稀疏那里有没有千里的任何文件,我的搜索功能将不能与radius=12000(12公里)返回任何东西。无论我在哪里,我都希望它将最接近的文档返回给我。如何通过一次调用Search API来实现这一点?

回答

5

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

从本质上讲,您希望将查询的“点击次数”降低到10k,这对于您查询的内容是有意义的。 可以在至少几个方法,你可以结合起来解决这个问题:

  • 添加一个排名,让最“重要”的文档(通过某些标准是有道理的在你的域)在返回等级顺序,然后这些将按距离排序。
  • 过滤一个或多个文档字段(例如,'业务类别',如果您的文档包含有关企业的信息)以减少候选文档的数量。

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

+0

感谢您确认@Middy和我推测在幕后发生了什么。知道'命中'限制是10k肯定有帮助。为了完成,我将陈述答案**我希望它能够将最接近的文档返回给我,无论我身在何处。我怎样才能实现这一致的调用Search API?**是我不能一致如果我的搜索半径_might_包含超过10k文件 - 不幸的是我的应用程序可能会做:( – Dan 2013-03-13 21:00:12

1

我有完全相同的问题,我不认为它是可能的。问题发生在你自己发现有更多可能的结果比返回的结果时。 Google算法会在加载限制时退出,然后对结果进行排序。

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

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

+0

从实用的角度来看,如果你知道你最密集的'GeoPoint'簇可能是多么密集的话,黑客就可以工作。 (以Search API配额为代价)。但是,如果您不知道最密集的集群有多密集,那么在您不知情的情况下,子行业可能会遭遇出现错误结果的相同问题。在我的情况下,每天有20,000个Search API调用没有留下太多空间让每个用户请求的呼叫数加倍。 – Dan 2013-03-11 22:56:13

0

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

相关问题