基于皇家邮政 PAF 原始数据构建邮政编码地址查找
Posted
技术标签:
【中文标题】基于皇家邮政 PAF 原始数据构建邮政编码地址查找【英文标题】:Building postcode address lookup based on Royal Mail PAF Raw data 【发布时间】:2011-05-06 09:47:54 【问题描述】:我正在开发基于 Royal Mail PAF 数据的用于邮政编码查找的自定义构建软件。该软件的主要目的是替代快速地址(第三方软件供应商)。
我有几个问题
为什么包含索引的快速地址数据文件小于 500MB,而如果您查看 PAF 原始数据,它会超过 2.50GB。他们对原始数据执行了哪些清理和压缩技术来实现这一目标。我导入的 Db 大小为 2.50GB (sqlite)。我必须使用一些免费/开源的 Db,而付费 Db 不是我的选择。
有 2800 万条记录。例如,考虑到可以使用“LIKE”语句执行搜索,我如何改进按组织名称或城镇的搜索?
有什么想法吗?
【问题讨论】:
只是出于兴趣,PAF 现在免费了吗? 【参考方案1】:不要存储您不需要的信息,例如 DPS、占用率和各种公司标志
您可以为每个邮政编码保留 180 万个地址,而不是保存 2800 万个地址,并为每个邮政编码(即门牌号、房屋/建筑物名称)提供一个分配点列表
我不确定您使用的是哪个版本的 PAF,是带键的关系版本还是扩展版本。
键控版本将减小文件大小,因为您只需要由指向位置、街道、街道末端等查找表的数字组成的地址。但是在地址中使用键将无助于按组织或城镇名称进行搜索。
视图将帮助您从键格式化您的输出地址。确保您使用的数据库具有可以使用索引的视图,否则您将最终进行表扫描。
我过去所做的是使用全文搜索引擎 sphinx http://sphinxsearch.com/ 为 PAF 编制索引,它可以为您决定索引的任何单词提供非常强大的搜索(包括部分单词和模糊匹配)。尝试地址中的所有单词。 sphinx 的结果是一个键列表,可用于遍历 sql 结果集。 sql 查询可以针对可用于从查找表构建完整地址的键的地址表。 sphinx 索引构建速度非常快,并且生成的索引大小非常小。
对于这种大小的数据库,mysql 可能比 sqlite 更适合。
其他需要考虑的事情。 你是在做批处理还是只是事务性的——忘记 sphinx 进行批处理。 更新频率。如果您不每月更新,那么您很快就会过时。
注意:如果您有 PAF 的键控版本,则有一些用于格式化地址的可怕规则和许多未记录的例外情况。
【讨论】:
嗨,DGD,解释得很好。我一定会将此标记为我的答案。我使用的是 PAF 的键控版本,它本月(2011 年 5 月)刚到货。当涉及到任何搜索时,我被卡住了。 Infact 用户可以键入任何组合,例如组织 + 城镇或街道名称 + 城镇或门牌 + 街道 + 城镇等组合。搜索位位于不同的键控表中。如何使用所有这些关键表完成搜索。抱歉,我目前不熟悉狮身人面像。我现在要详细研究一下。我会及时通知您。【参考方案2】:文件大小对您来说是个问题吗?如果文件大小很重要,我只会担心压缩 - 它几乎不再这样做了,而且在大多数情况下,2.5 GB 并不令人望而却步。
如果您确实必须压缩数据,您几乎肯定无法使用现成的数据库系统;我猜 Quick Address 使用 ZIP 之类的东西来压缩数据。
至于第二个问题 - 你能举一个你的表的例子,以及你想要优化的查询类型吗?在大多数邮政编码查找系统中,唯一重要的查询是按邮政编码搜索并返回匹配的地址;只要您为邮政编码列编制了索引,无论您有多少条记录,这都应该非常快。
【讨论】:
【参考方案3】:您想尝试空间填充曲线或空间索引。 sfc 将 2d 复杂度降低到 1d 复杂度。我用邮政编码搜索做了类似的事情。您想在 phpclasses.org (hilbert-curve) 上查看我的 sfc 的 php 实现。您想查找 Nick 的希尔伯特曲线四叉树空间索引博客。
对于城市名称查找,您要查找 trie 数据结构。 trie 是一种字典数据结构。您想在 phpclasses.org (kart-trie) 上查看我在 php 中的 kart-trie 实现。最坏情况的复杂度是 IMO log(n+k),其中 n 是字符串长度,k 是密钥长度。您希望将 kart-trie 转换为嵌套集,因为 kart-trie 与 radix-trie 或 crit-bit trie 不同,因此每个节点只有 2 个叶子。您要查找 php trie 和通配符 http://phpir.com/tries-and-wildcards。
【讨论】:
【参考方案4】:我赞同 Tom Gurney 的观点……你做了很多工作却没有什么好处。此外,您还要负责随时更新数据 - 额外的工作。
我假设您正在将邮政编码查找插入网站或内部应用程序?
有一些托管服务提供商可以为您完成这项工作,而且您的成本可能比直接使用 Royal Mail 更低,而且一旦集成,您几乎不需要动一根手指......
我在 CraftyClicks 工作,这是一家 PAF 解决方案提供商,所以在这里有一些既得利益.....http://www.craftyclicks.co.uk/
【讨论】:
【参考方案5】:除了邮局的 PAF,您还可以使用 192.com 网站查找地址。
过去几个月我一直在成功使用这种方法,并且没有遇到任何问题。
这是我的查找类。
Imports System.Net
Imports System.IO
Public Class PCLookup
Property Addresses As List(Of Address)
Public Sub New(Postcode As String)
GetAddresses(CreatDoc(Postcode))
End Sub
Private Function CreatDoc(PostCode As String) As mshtml.HTMLDocument
Dim URL As String = FormatPostcode(PostCode)
If URL = "" Then Return New mshtml.HTMLDocument
Dim request As HttpWebRequest = WebRequest.Create(URL)
Dim response As HttpWebResponse = request.GetResponse()
Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
Dim doc As New mshtml.HTMLDocument
Dim objDoc As mshtml.IHTMLDocument2 = doc
Dim param As Object() = reader.ReadToEnd()
objDoc.write(param)
response.Close()
reader.Close()
Return objDoc
End Function
Private Function FormatPostcode(Postcode As String) As String
Dim FullURL As String = "http://www.192.com/places/"
Do Until Postcode.Contains(" ") = False
Postcode = Replace(Postcode, " ", "")
Loop
If Len(Postcode) > 7 Or Len(Postcode) < 5 Then
Return ""
End If
If Len(Postcode) = 5 Then
FullURL &= Mid(Postcode, 1, 1) & "/"
FullURL &= Mid(Postcode, 1, 2) & "-" & Mid(Postcode, 3, 1) & "/"
FullURL &= Mid(Postcode, 1, 2) & "-" & Mid(Postcode, 3) & "/"
End If
If Len(Postcode) = 6 Then
If IsNumeric(Mid(Postcode, 2, 1)) Then
FullURL &= Mid(Postcode, 1, 1) & "/"
FullURL &= Mid(Postcode, 1, 3) & "-" & Mid(Postcode, 4, 1) & "/"
FullURL &= Mid(Postcode, 1, 3) & "-" & Mid(Postcode, 4) & "/"
Else
FullURL &= Mid(Postcode, 1, 2) & "/"
FullURL &= Mid(Postcode, 1, 3) & "-" & Mid(Postcode, 4, 1) & "/"
FullURL &= Mid(Postcode, 1, 3) & "-" & Mid(Postcode, 4) & "/"
End If
End If
If Len(Postcode) = 7 Then
FullURL &= Mid(Postcode, 1, 2) & "/"
FullURL &= Mid(Postcode, 1, 4) & "-" & Mid(Postcode, 5, 1) & "/"
FullURL &= Mid(Postcode, 1, 4) & "-" & Mid(Postcode, 5) & "/"
End If
Return FullURL
End Function
Private Sub GetAddresses(ObjDoc As mshtml.HTMLDocument)
Dim Obj As mshtml.IHTMLElementCollection = ObjDoc.getElementsByTagName("td")
Addresses = New List(Of Address)
For Each TD As mshtml.HTMLTableCell In Obj
If TD.className = "address" Then
Dim FullAddress As String = TD.innerText
Addresses.Add(New Address(FullAddress))
End If
Next
End Sub
End Class
还有地址类
Public Class Address
Property Line1 As String
Property Line2 As String
Property Line3 As String
Property Line4 As String
Property Postcode As String
Public Sub New(FullAddress As String)
Dim Obj As Object = Split(FullAddress, ", ")
Select Case UBound(Obj)
Case 4
Line1 = Obj(0) & " " & Obj(1)
Line2 = ""
Line3 = Obj(2)
Line4 = Obj(3)
Postcode = Obj(4)
Case 5
Line1 = Obj(0) & " " & Obj(1)
Line2 = Obj(2)
Line3 = Obj(3)
Line4 = Obj(4)
Postcode = Obj(5)
Case 6
Line1 = Obj(0) & " " & Obj(1)
Line2 = Obj(2) & " " & Obj(3)
Line3 = Obj(4)
Line4 = Obj(5)
Postcode = Obj(6)
End Select
End Sub
End Class
我希望这对其他人有用。
丰富。
【讨论】:
【参考方案6】:取决于您的具体要求。
频率:您可以获得一组一次性的数据文件,每年或每月,这取决于您的数据需要保持多长时间。有一个包含 2 个城镇地址(约克和其他地方)的免费示例数据库可供试用并开始构建。
类型:您每次可以获得一整套数据文件,或者您必须自己应用更改的增量。
结构:正如 DGD 所说,您可以键控或扩展。
如果您需要新地址,使用增量,考虑到 RM 每个月都会进行数千次更改,不仅仅是添加,还有删除、合并地址和转换(商业 住宅),这将是一项巨大的工作自己申请。尤其是在维护唯一的地址密钥方面,这些密钥也可以在您自己的应用程序数据库的其他地方使用。
基于每月完整数据文件,扩展,包括新注册地址的'NotYetBuilt'文件,我构建了一个系统每月重新加载整个数据集,分为2部分:1.)下载最后一组数据, 将文件等展开到磁盘和 2).将新数据加载到数据库中
对于第 2 部分,当您加载数据时,您可以随时为每个条目构建一个完整的地址字符串(以返回搜索匹配项)。由于有超过 3100 万个地址,您不能使用 LIKE 或常规搜索语法。跨要用于搜索的字段构建 FULLTEXT 索引,并构建存储过程以使用 CONTAINSTABLE for FREETEXT 进行搜索。
比我预期的更容易构建,困难在于:处理多个文件,每个文件最多包含 31+ 百万条记录,当前和新地址位于不同的文件中,没有“县”值(它们是正式的2000 年从英国地址删除)它们位于不同的文件中,以便在需要时加载,等等。
【讨论】:
以上是关于基于皇家邮政 PAF 原始数据构建邮政编码地址查找的主要内容,如果未能解决你的问题,请参考以下文章