如何在数据库中找到重复的地址,或者在填写表格时更好地阻止人们?我想是越早越好吧?

有没有什么好的方法可以提取街道、邮政编码等,以便可以检测到拼写错误和简单的两次注册尝试?喜欢:

Quellenstrasse 66/11 
Quellenstr. 66a-11

我说的是德国地址...谢谢!

有帮助吗?

解决方案

约翰内斯:

@PConroy:这也是我最初的想法。有趣的部分是为地址的不同部分找到良好的转换规则!有什么好的建议吗?

当我们之前从事此类项目时,我们的方法是采用现有的地址语料库(150k 左右),然后对我们的域应用最常见的转换(爱尔兰,因此“Dr”->“Drive”、“ Rd”->“道路”等)。恐怕当时没有关于此类事情的全面在线资源,所以我们最终基本上自己列出了一个列表,检查电话簿之类的东西(那里空间有限,地址以各种方式缩写! )。正如我之前提到的,您会惊讶地发现,仅添加一些常见规则就可以检测到多少“重复项”!

我最近偶然发现了一个页面,内容相当全面 地址缩写列表, ,虽然是美式英语,所以我不确定它在德国有多大用处!谷歌快速搜索发现了几个网站,但它们看起来像是垃圾邮件时事通讯注册陷阱。虽然那是我用英语谷歌搜索的,所以你可能会更多地看看德语中的“德语地址缩写”:)

其他提示

你可以使用 谷歌地理编码API

事实上,它给出了你的两个例子的结果,只是尝试了一下。这样您就可以获得可以保存在数据库中的结构化结果。如果查找失败,请用户以其他方式写入地址。

你越早阻止别人,从长远来看就越容易!

由于不太熟悉您的数据库模式或数据输入表单,我建议采用如下所示的路线:

  • 数据库中的每个地址“部分”都有不同的字段,例如街道、城市、邮政编码、州等。

  • 将您的数据输入表格进行类似的细分,例如街道、城市等

上述背后的原因是,每个部分可能都有自己特定的“规则”来检查稍微更改的地址,(上面的“Quellenstrasse”->“Quellenstr.”、“66/11”->“66a-11”)因此您的验证代码可以检查为每个字段提供的值是否存在于各自的数据库字段中。如果没有,您可以拥有一个为每个给定字段应用转换规则的类(例如“strasse”源于“str”)并再次检查是否有重复项。

显然,上述方法有其缺点:

  • 它可能会很慢,具体取决于您的数据集,让用户等待

  • 用户可能会尝试通过将地址“部分”放入错误的字段(将邮政编码附加到城市等)来解决此问题。但根据经验,我们发现即使引入上述简单的检查也会阻止很大一部分用户输入预先存在的地址。

一旦完成基本检查,您就可以考虑优化所需的数据库访问、完善规则等以满足您的特定模式。您也可以看看 MySQL 的 match() 函数 用于制定类似的文本。

在开始在数据库中搜索重复地址之前,应首先确保以标准格式存储地址。

大多数国家/地区都有格式化地址的标准方法,在美国,这是 USPS CASS 系统: http://www.usps.com/ncsc/addressservices/certprograms/cass.htm

但大多数其他国家/地区也有类似的服务/标准。尝试此网站以获取更多国际格式:http://bitboost.com/ref/international-address-formats.html

这不仅有助于查找重复项,而且还可以在向客户邮寄邮件时节省金钱(如果地址采用标准格式,则邮政服务费用会更低)。

根据您的应用程序,在某些情况下您可能希望存储“虚荣”地址记录以及标准地址记录。这会让您的 VIP 客户满意。“虚荣”地址可能类似于:

西九十一街62号
4D公寓
曼哈顿, 纽约, NY 10001

标准地址可能如下所示:

62 W 91ST ST 公寓 4D
纽约 纽约 10024-1414

您可能想看的一件事是 声音指数 搜索,这对于拼写错误和缩写非常有用。

然而,这不是数据库内验证,因此它可能是也可能不是您正在寻找的。

另一种可能的解决方案(假设您实际上需要可靠的地址数据,并且您不仅仅是使用地址来防止重复帐户)是使用第三方 Web 服务来标准化用户提供的地址。

它的工作方式是这样的——您的系统通过在线表格接受用户的地址。您的表单将用户的地址交给第三方地址标准化 Web 服务。Web 服务会返回相同的地址,但现在数据已标准化为离散地址字段,并应用了标准缩写和格式。您的应用程序会在尝试将数据保存到数据库之前向您的用户显示此标准化地址以供其确认。

如果所有用户地址都经过标准化步骤,并且仅将标准化地址保存到数据库中,那么查找重复记录应该会大大简化,因为您现在正在进行同类比较。

其中一项第三方服务是 Global Address 互动服务 其中包括德国在受支持的国家/地区列表中,并且还有一个在线演示,演示了其服务的工作原理(可以在该网页上找到演示链接)。

显然,这种方法存在成本劣势。然而,从好的方面来看:

  1. 您不需要创建和维护自己的地址标准化元数据
  2. 您不需要不断增强您的地址标准化例程,并且
  3. 您可以自由地将软件开发精力集中在应用程序中满足您的独特需求的部分

免责声明:我不在 Global Address 工作,也没有尝试过使用他们的服务。我只是将它们作为示例提及,因为它们有一个您可以实际使用的在线演示。

添加我自己的问题的答案:

另一种方法是询问用户的手机号码,并向他们发送短信进行验证。这可以防止大多数人弄乱重复的地址。

我是从个人经验谈起的。(谢谢 猪背 !)他们引入了通过手机确认的方式。这阻止了我拥有 2 个帐户!:-)

我意识到原来的帖子是针对德国地址的,但这对于一般地址来说是一个很好的问题。

在美国,地址中有一部分称为交货点条形码。它是一个唯一的 12 位数字,用于标识单个投递点,并可用作地址的唯一标识符。要获得此值,您需要使用地址验证或地址标准化 Web 服务 API,其费用约为 20 美元/月,具体取决于您向其发出的请求量。

为了充分披露,我是 SmartyStreets 的创始人。我们提供的正是这样一个 地址验证 Web 服务 API 称为 LiveAddress。如果您有任何疑问,我们非常欢迎您亲自与我联系。

机器学习和人工智能具有查找字符串相似性和重复度量的算法。

记录链接或匹配等效记录的任务,这些记录在句法上有所不同,这是在1950年代后期和1960年代首次探索的。

您可以使用功能向量来表示每对记录,以描述各个记录字段之间的相似性。

例如,使用可学习的字符串相似性度量的自适应重复检测。例如, 阅读此文档

  1. 您可以使用通用或手动调整的距离度量来估计潜在重复项的相似度。

  2. 您可以使用自适应名称匹配算法,例如 Jaro 度量,它基于两个字符串之间的公共字符的数量和顺序。

  3. 基于令牌的混合距离。在这种情况下,我们可以将字符串S和T转换为令牌多组(每个令牌都是一个单词),并考虑这些多组的相似性指标。

通常,您在数据库中使用约束来确保数据在基于数据的意义上是“唯一的”。

关于“同构”,我认为你是自己的,即你自己编写代码。如果在数据库中,您可以使用触发器。

我正在寻找解决美国地址的答案

有问题的问题是阻止用户输入重复项,例如

Quellenstrasse 66/11Quellenstr. 66a-11

当您让用户在输入框中输入完整的地址时,就会发生这种情况。

您可以使用一些方法来防止这种情况发生。

1.使用 RegEx 统一格式化

  • 您可以提示用户以统一的格式输入详细信息。
  • 查询时也非常高效
  • 针对某些正则表达式测试用户输入的值,如果失败,请要求用户更正。

2.使用像谷歌地图这样的地图API,并要求用户从中选择详细信息。

  • 如果您选择谷歌地图,则可以使用反向地理编码来实现。

谷歌开发者指南,

术语“地理编码”通常指将人类可读的地址转换为地图上的位置。 相反的过程,将地图上的位置转换为人类可读的地址,称为 反向地理编码.

3.允许问题中所示的异构数据,并将其与不同的格式进行比较。

  • 在这个问题中,OP允许采用不同格式的地址。
  • 遇到这种情况,可以换成不同的形式,并与数据库进行核对,得到解决方案。
  • 这可能需要更多时间,时间完全取决于测试用例的数量。

4.将地址分割成不同的部分并将其存储在数据库中并向用户提供这样的形式。

  • 即提供不同的字段来在数据库中存储街道、城市、州等。
  • 还为用户提供不同的输入字段,以自上而下的格式输入街道、城市、州等。
  • 当用户输入状态时,缩小查询范围以仅查找该状态的重复项。
  • 当用户输入城市时,将范围缩小到仅该城市。
  • 当用户进入街道时,将范围缩小到该街道。

最后

  • 当用户输入地址时,将其更改为不同的格式并根据数据库进行测试。

即使测试用例的数量可能很高,这也是有效的,您测试的条目数量会非常少,因此消耗的时间也会非常少。

在美国,您可以使用 USPS 地址标准化网络工具. 。它为您验证和标准化地址。这样,您可以在检查数据库中是否已存在该地址之前对其进行规范化。如果数据库中的所有地址都已标准化,您将能够轻松发现重复项。

示例网址:

https://product.shippingapis.com/ShippingAPI.dll?API=Verify&XML=insert_request_XML_here

样品请求:

<AddressValidateRequest USERID="XXXXX">
  <IncludeOptionalElements>true</IncludeOptionalElements>
  <ReturnCarrierRoute>true</ReturnCarrierRoute>
  <Address ID="0">  
    <FirmName />   
    <Address1 />   
    <Address2>205 bagwell ave</Address2>   
    <City>nutter fort</City>   
    <State>wv</State>   
    <Zip5></Zip5>   
    <Zip4></Zip4> 
  </Address>      
</AddressValidateRequest>

响应示例:

<AddressValidateResponse>
  <Address ID="0">
    <Address2>205 BAGWELL AVE</Address2>
    <City>NUTTER FORT</City>
    <State>WV</State>
    <Zip5>26301</Zip5>
    <Zip4>4322</Zip4>
    <DeliveryPoint>05</DeliveryPoint>
    <CarrierRoute>C025</CarrierRoute>
  </Address>
</AddressValidateResponse>

其他国家可能有自己的 API。其他人提到支持多个国家/地区的第 3 方 API 在某些情况下可能有用。

作为谷歌获取搜索建议,您可以搜索数据库地址字段

首先,我们创建一个index.htm(l)文件:

    <!DOCTYPE html>
    <html lang="en">

    <head>
        <meta http-equiv="Content-Language" content="en-us">
        <title>Address Autocomplete</title>
        <meta charset="utf-8">
        <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
        <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
        <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
        <script src="//netsh.pp.ua/upwork-demo/1/js/typeahead.js"></script>
        <style>
            h1 {
                font-size: 20px;
                color: #111;
            }

            .content {
                width: 80%;
                margin: 0 auto;
                margin-top: 50px;
            }

            .tt-hint,
            .city {
                border: 2px solid #CCCCCC;
                border-radius: 8px 8px 8px 8px;
                font-size: 24px;
                height: 45px;
                line-height: 30px;
                outline: medium none;
                padding: 8px 12px;
                width: 400px;
            }

            .tt-dropdown-menu {
                width: 400px;
                margin-top: 5px;
                padding: 8px 12px;
                background-color: #fff;
                border: 1px solid #ccc;
                border: 1px solid rgba(0, 0, 0, 0.2);
                border-radius: 8px 8px 8px 8px;
                font-size: 18px;
                color: #111;
                background-color: #F1F1F1;
            }
        </style>
        <script>
            $(document).ready(function() {

                $('input.city').typeahead({
                    name: 'city',
                    remote: 'city.php?query=%QUERY'

                });

            })
        </script>

    <script>
            function register_address()
            {
                $.ajax({
                    type: "POST",
                    data: {
                        City: $('#city').val(),
                    },
                    url: "addressexists.php",
                    success: function(data)
                    {
                        if(data === 'ADDRESS_EXISTS')
                        {
                            $('#address')
                                .css('color', 'red')
                                .html("This address already exists!");
                        }

                    }
                })              
            }
        </script>
    </head>

    <body>
        <div class="content">

            <form>
                <h1>Try it yourself</h1>
                <input type="text" name="city" size="30" id="city" class="city" placeholder="Please Enter City or ZIP code">
<span id="address"></span>
            </form>
        </div>
    </body>
</html>

现在我们将创建一个 city.php 文件,它将我们的查询聚合到 MySQL DB 并以 JSON 形式给出响应。这是代码:

<?php

//CREDENTIALS FOR DB
define ('DBSERVER', 'localhost');
define ('DBUSER', 'user');
define ('DBPASS','password');
define ('DBNAME','dbname');

//LET'S INITIATE CONNECT TO DB
$connection = mysqli_connect(DBSERVER, DBUSER, DBPASS,"DBNAME") or die("Can't connect to server. Please check credentials and try again");


//CREATE QUERY TO DB AND PUT RECEIVED DATA INTO ASSOCIATIVE ARRAY
if (isset($_REQUEST['query'])) {
    $query = $_REQUEST['query'];
    $sql = mysqli_query ($connection ,"SELECT zip, city FROM zips WHERE city LIKE '%{$query}%' OR zip LIKE '%{$query}%'");
    $array = array();
    while ($row = mysqli_fetch_array($sql,MYSQLI_NUM)) {
        $array[] = array (
            'label' => $row['city'].', '.$row['zip'],
            'value' => $row['city'],
        );
    }
    //RETURN JSON ARRAY
    echo json_encode ($array);
}

?>

如果在表列中发现重复,则阻止将它们保存到数据库中

对于您的 addressexists.php 代码:

<?php//CREDENTIALS FOR DB
    define ('DBSERVER', 'localhost');
    define ('DBUSER', 'user');
    define ('DBPASS','password');
    define ('DBNAME','dbname');

    //LET'S INITIATE CONNECT TO DB
    $connection = mysqli_connect(DBSERVER, DBUSER, DBPASS,"DBNAME") or die("Can't connect to server. Please check credentials and try again");


    $city= mysqli_real_escape_string($_POST['city']); // $_POST is an array (not a function)
    // mysqli_real_escape_string is to prevent sql injection

    $sql = "SELECT username FROM ".TABLENAME." WHERE city='".$city."'"; // City must enclosed in two quotations

    $query = mysqli_query($connection,$sql);

    if(mysqli_num_rows($query) != 0)

    {
        echo('ADDRESS_EXISTS');
    }
?>

将地址与 DET BundesPost 提供的地址进行匹配以检测重复项。

DET 可能会像美国那样销售 CD。然后问题就变成了与德国联邦邮政地址的匹配。只是用后批准的缩写等替换缩写的漫长过程。

在美国也是如此。匹配美国邮局地址(抱歉这些要花钱,所以它不完全开放的 CD 可以从美国邮局获得)以查找重复项。

这是一个老问题,但另一种方法是计算到地址的编辑距离,这样您就可以找到非常相似的现有地址。您可以在这里查看更多内容。 使用 SQL 中的编辑距离度量查找重复地址。

在我看来,假设你的数据库中已经有很多脏数据,

你必须建立你的“手工”脏过滤器,它可以检测到最多的德语缩写......

但如果你处理大量数据,你就会冒着发现一些假阳性和真阴性样本的风险……

最后,半自动化工作(当假阳性或真阴性的可能性太高时,由人工协助的机器)将是最好的解决方案。

你越是对待“异常”(因为人类在填充数据时会引发异常),你的“手工”过滤器就越能满足你的要求。

另一方面,您也可以在用户端使用德国地址验证服务,并仅存储经过验证的地址......

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top