基于Royal Mail PAF Raw数据构建邮政编码地址查找

时间:2011-05-06 09:47:54

标签: sql compression query-optimization postal-code

我正在开发基于Royal Mail PAF数据的邮政编码查找自定义构建软件。该软件的主要目的是取代快速地址(第三方软件供应商)。

我有几个问题

  1. 为什么包含索引的快速地址数据文件低于500MB,而如果查看PAF原始数据,则超过2.50GB。他们对原始数据执行了哪些清理和压缩技术来实现这一目标。我导入的Db大小是2.50GB(sqlite)。我必须使用一些免费/开源的Db和付费Db不是我的选择。

  2. 有2800万条记录。如何根据组织名称或城镇改进搜索,例如考虑可以使用“LIKE”语句执行搜索?

  3. 有什么想法吗?

6 个答案:

答案 0 :(得分:0)

文件大小是否适合您?如果文件大小很重要,我只会担心压缩 - 它几乎不再存在,并且在大多数情况下2.5 GB并不是禁止的。

如果你真的必须压缩数据,你几乎肯定无法使用现成的数据库系统;我猜这个快速地址使用类似ZIP的东西来压缩数据。

关于第二个问题 - 您能举例说明您的表格,以及您想要优化的查询类型吗?在大多数邮政编码查找系统中,唯一重要的查询是通过邮政编码进行搜索并返回匹配的地址;只要您将邮政编码列编入索引,无论您有多少记录,这都应该非常快。

答案 1 :(得分:0)

您想尝试空间填充曲线或空间索引。 sfc将2d复杂度降低到1d复杂度。我用邮政编码搜索做了类似的事情。你想在phpclasses.org(hilbert-curve)看看我的php实现sfc。你想寻找尼克的希尔伯特曲线四叉树空间索引博客。

对于cityname查找,您要查找trie数据结构。特里是字典数据结构。你想在phpclasses.org(kart-trie)中查看我的kart-trie实现。最坏情况的复杂性是IMO log(n + k),其中n是字符串长度,k是密钥长度。你想将kart-trie转换为嵌套集,因为kart-trie不同于radix-trie或者暴击比特,因此它每个节点只有2个叶子。你想寻找php trie和通配符http://phpir.com/tries-and-wildcards

答案 2 :(得分:0)

不要存储您不需要的信息,例如DPS,占用率和各种公司标志

不是持有2800万个地址,而是可以为每个邮政编码保存一个1.8米地址,并为每个邮政编码(即门牌号码,房屋/建筑物名称)提供一个优惠点列表

我不确定您拥有哪个版本的PAF,带密钥或扩展版本的关系版本。

键控版本将减小文件大小,因为您只需要由指向地点,街道,街道等的查找表的数字组成的地址。但是在您的地址中使用密钥将无助于按组织或城镇名称搜索。

视图将有助于从键格式化输出地址。确保您使用的数据库具有可以使用索引的视图,否则您将最终进行表扫描。

我过去所做的事情是使用全文搜索引擎sphinx http://sphinxsearch.com/为PAF编制索引,它可以为您决定索引的任何单词提供非常强大的搜索功能(包括部分单词和模糊匹配)。尝试地址中的所有单词。 sphinx的结果是一个键列表,您可以使用它来通过SQL结果集进行迭代。 sql查询可以针对可用于从查找表构建完整地址的键的地址表。 sphinx索引构建速度非常快,并且索引大小非常小。

对于此大小的数据库,Mysql可能比sqlite更合适。

需要考虑的其他事项。 您正在进行批处理还是只进行交易 - 忘记sphinx进行批处理。 更新频率。如果你不每月更新,你将在很短的时间内变得过时。

注意:如果您拥有PAF的键控版本,则格式化地址和许多未记录的异常会有一些可怕的规则。

答案 3 :(得分:0)

我的第二个汤姆格尼的观点......你做了很多工作而收效甚微。此外,您承担着更新数据的责任 - 额外的工作。

我假设您将邮政编码查询插入网站或内部应用程序?

有一些托管服务提供商可以为您完成工作,而且您的费用可能比直接转到皇家邮政要低,而且一旦集成了物品,您几乎不需要抬起手指....

我为PAF解决方案提供商CraftyClicks工作,所以在这里有一些既得利益..... http://www.craftyclicks.co.uk/

答案 4 :(得分:0)

除邮局的PAF外,您可以使用192.com网站查找地址。

过去几个月我一直在成功使用这种方法,没有任何问题。

这是我的Lookup类。

    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

我希望这对其他人有用。

答案 5 :(得分:0)

取决于您的确切要求。

频率:您可以获取一组一次性的数据文件(年度或每月),因此取决于数据的最新程度。有2个城镇地址(约克和其他地方)的免费示例数据库,可以尝试并开始使用。

类型:您每次都可以获得完整的数据文件集,或者您必须自己应用更改的增量。

结构:正如DGD所说,您可以进行抠像或扩展。

如果您需要使用三角洲的新地址,则考虑到RM每个月进行成千上万的更改,不仅是增加,而且删除,合并地址和转换(企业<->住宅)将是大量的工作运用自己。特别是在维护唯一的地址密钥方面,这些地址密钥也可能在您自己的应用程序数据库的其他地方使用。

基于扩展的每月完整数据文件,其中包括新注册地址的“ NotYetBuilt”文件,我构建了一个系统来每月重新加载整个数据集,分为2部分:1.)下载了最后一组数据,将文件等扩展到磁盘上,然后2)。将新数据加载到数据库中

对于第2部分,在加载数据时,您可以在进行操作时为每个条目构造一个完整的地址字符串(以返回搜索匹配项)。由于地址超过3100万,因此您不能使用LIKE或常规搜索语法。在要用于搜索的字段上建立FULLTEXT索引,并使用存储的过程使用CONTAINSTABLE进行FREETEXT的搜索。

比我预期的要容易构建,困难在于:处理多个文件,每个文件中有多达31+百万条记录,当前和新地址位于不同文件中,没有“ County”值(它们是正式的在2000年从英国地址中删除),如果需要,它们位于其他文件中进行加载等。