我正在尝试创建一个Python脚本,它将地址作为输入,并在多次匹配的情况下吐出纬度和经度,或纬度和经度,就像Nominatim一样。
因此,可能的输入和输出可能是: -
在上面的6中,纽约被归还,因为找不到地址为103 Alkazam, New York, USA
的地方,但它至少可以找到New York, USA
。
最初,我想到构建一个树,表示兄弟姐妹按字母顺序排序的层次结构关系。它可能是这样的: -
GLOBAL
|
---------------------------------------------
| | ...
USA
---------------
| | ...
CALIFORNIA NEW YORK
| |
----------- -------------
| |.. | |....
PEARL STREET PEARL STREET
但问题是用户可以提供不完整的地址,如2,4和5。
因此,我接下来想到使用搜索树并在每个节点中存储完全限定的地址。但这也是非常糟糕的: -
我有一个附加要求。我需要检测拼写错误。我想这必须作为一个单独的问题来处理,并且可以将每个节点视为通用字符串。
更新1
一点阐述。输入将是一个列表,其中较低索引上的项是较高索引中项的父项;他们当然可能是也可能不是直接的父母或孩子。因此,对于查询1,输入将是["USA", "NEW YORK"]
。因此,USA, New York
没有返回结果是完全正常的。
如果建筑物有地址并且我们的数据非常详细,用户应该能够找到建筑物。
更新2(省略案例)
如果用户查询Pearl Street, USA
,那么我们的算法应该能够找到该地址,因为它知道Pearl Street
已将New York
作为父级,USA
是其父级。
更新3(剩余案例)
假设用户查询101 C, Alley A, Pearl Street, New York
。另外,假设我们的数据确实知道101 C
但不知道Alley A
。根据它101 C
是Pearl Street
的直接孩子。即使在这种情况下,它也应该能够找到地址。
答案 0 :(得分:2)
感谢所有人的回答,他们的答案很有帮助,但没有解决我需要的一切。我终于找到了一种处理我所有案件的方法。该方法是我在问题中建议的修改版本。
这里我将引用一个名为'node'的东西,它是一个类对象,它将包含地理信息,如地点实体的纬度,经度,也可能是维度,以及它的完整地址。
如果该实体的地址是'101 C,Pearl Street,New York,USA',那么这意味着我们的数据结构将至少有四个节点 - '101 C','Pearl Street','New York '和'美国'。每个节点都有一个name
和一个address
部分。对于'101 C',name
将是'101 C',地址将是'Pearl Street,New York,USA'。
基本思想是拥有这些节点的搜索树,其中节点name
将用作搜索的关键字。我们可能会得到多个匹配项,因此稍后我们需要根据节点address
与查询的匹配项的匹配程度对结果进行排名。
EARTH
|
---------------------------------------------
| |
USA INDIA
| |
--------------------------- WEST BENGAL
| | |
NEW YORK CALIFORNIA KOLKATA
| | |
--------------- PEARL STREET BARA BAZAR
| | |
PEARL STREET TIME SQUARE 101 C
| |
101 C 101 C
假设我们有如上所述的地理数据。因此,搜索“101 C,纽约”不仅会返回“纽约”中的“101 C”节点,还会返回“印度”节目中的“101 C”节点。这是因为算法将仅使用name
,即“101 C”来搜索节点。稍后,我们可以通过测量节点address
与查询地址的差异来评估结果的质量。我们没有使用完全匹配,因为允许用户提供不完整的地址,如本例所示。
要对结果的质量进行评分,我们可以使用Longest Common Subsequence。在这个算法中,“遗漏”和“剩余”案件得到妥善处理。
我最好让代码进行交谈。下面是为此目的而定制的Python实现。
def _lcs_diff_cent(s1, s2):
"""
Calculates Longest Common Subsequence Count Difference in percentage between two strings or lists.
LCS reference: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem.
Returns an integer from 0-100. 0 means that `s1` and `s2` have 0% difference, i.e. they are same.
"""
m = len(s1)
n = len(s2)
if s1 == s2:
return 0
if m == 0: # When user given query is empty then that is like '*'' (match all)
return 0
if n == 0:
return 100
matrix = [[0] * (n + 1)] * (m + 1)
for i in range(1, m+1):
for j in range(1, n+1):
if s1[i-1] == s2[j-1]:
matrix[i][j] = matrix[i-1][j-1] + 1
else:
matrix[i][j] = max(matrix[i][j-1], matrix[i-1][j])
return int( ( 1 - float(matrix[m][n]) / m ) * 100 )
我秉承上述(基本)方法,因为它强制裁员,并且如果用户在他的查询中提供了“USA”,那么我们无需查看“印度”中的节点,这无法削减杠杆率。 / p>
这种优化的方法在很大程度上解决了上述问题。解决方案是没有一个大的搜索树。我们可以将搜索空间划分为“USA”和“INDIA”。稍后我们可以进一步对这些搜索空间进行状态重新分区。这就是我所说的'切片'。
在下图中,SearchSlice
表示“切片”,SearchPool
表示搜索树。
SearchSlice()
|
---------------------------------------------
| |
SearchSlice(USA) SearchSlice(INDIA)
| |
--------------------------- SearchPool(WEST BENGAL)
| | |
SearchPool(NEW YORK) SearchPool(CALIFORNIA) |- KOLKATA
| | |- BARA BAZAR, KOLKATA
|- PEARL STREET |- PEARL STREET |- 101 C, BARA BAZAR, KOLKATA
|- TIME SQUARE
|- 101 C, PEARL STREET
|- 101 C, TIME SQUARE
上面几点要注意的几点......
SearchSlice(USA)
在“USA”中维护一段状态。因此,“纽约”下的节点在address
中不包含“纽约”或“美国”这个名称。其他地区也是如此。层次结构关系隐式定义完整地址。address
也包括其父级name
,因为它们没有被切片。如果存在存储桶(池),则存在隐式扩展可能性。我们(比如说)将“美国”的地理数据分成两组。两者都可以在不同的系统上。因此,如果'NEW YORk'池在系统A上,但'CALIFORNIA'池在系统B上,那是完全没问题的,因为它们不共享任何数据,当然除了父母。
这是警告。我们需要复制永远是切片的父母。由于切片的数量有限,因此层次结构不会太深,因此复制它们不应过于冗余。
请参阅我的GitHub了解working demo Python code。
答案 1 :(得分:1)
如何使用键值存储映射和全文搜索。
python.dict,memcached,mongodb ....将满足你的需要。
需要考虑的一些问题:
因此,更多可用的测试用例用于用户输入
情况101 C, Time Square, New York, US 101 C, Pearl street, New York, US 101 C, Time Square, SomeCity, Mars 101 C 101 C, US 101 C, New York, US 101 C, New York, Time Square, US North Door, 101 C, Time Square, New York, US South Door, 101 C, Time Square, New York, US
:
最佳解决方案 :(也是最复杂的)
您的计划/网站可能会像谷歌一样快速运行。
答案 2 :(得分:0)
如果您尝试为此问题创建数据结构,我认为您将拥有数据冗余。相反,你可以使用树/图和&尝试实现一种搜索算法,该算法根据节点值搜索用户输入的单词。 模糊匹配可以帮助您生成最可能的结果,并且您可以根据其相似性 - 引用的置信度建议/向用户显示其中的前几个。
这也可以处理拼写错误等。