6

我收到了一张大约有 18000 行的桌子。每条记录都描述了一个客户的位置。问题是,当这个人创建表时,他们没有添加“公司名称”字段,只有“位置名称”,一个公司可以有很多位置。

例如,以下是一些描述同一客户的记录:

位置表

 ID  Location_Name     
 1   TownShop#1        
 2   Town Shop - Loc 2 
 3   The Town Shop     
 4   TTS - Someplace   
 5   Town Shop,the 3   
 6   Toen Shop4        

我的目标是让它看起来像:

位置表

 ID  Company_ID   Location_Name     
 1   1            Town Shop#1       
 2   1            Town Shop - Loc 2 
 3   1            The Town Shop     
 4   1            TTS - Someplace   
 5   1            Town Shop,the 3   
 6   1            Toen Shop4        

公司表

 Company_ID  Company_Name  
 1           The Town Shop 

没有“公司”表,我必须从代​​表多个位置的最具描述性或最佳位置名称生成公司名称列表。

目前我在想我需要生成一个相似的位置名称列表,然后手动浏览该列表。

任何关于我如何解决这个问题的建议都值得赞赏。

@Neall,感谢您的发言,但不幸的是,每个位置名称都是不同的,没有重复的位置名称,只有相似。因此,在您的语句“repcount”的结果中,每一行都是 1。

@yukondude,您的第 4 步是我问题的核心。

4

5 回答 5

1

我以前不得不这样做。唯一真正的方法是手动匹配各个位置。使用数据库的控制台界面和分组选择语句。首先,添加您的“公司名称”字段。然后:

SELECT count(*) AS repcount, "Location Name" FROM mytable
 WHERE "Company Name" IS NULL
 GROUP BY "Location Name"
 ORDER BY repcount DESC
 LIMIT 5;

找出列表顶部的位置属于哪个公司,然后使用 UPDATE ... WHERE "Location Name" = "The Location" 语句更新您的公司名称字段。

PS - 你真的应该把你的公司名称和位置名称分成单独的表,并通过它们的主键来引用它们。

更新: - 哇 - 没有重复?你有多少记录?

于 2008-08-08T16:40:43.933 回答
1

请更新问题,您有可用的公司名称列表吗?我问是因为您也许可以使用 Levenshtein 算法来查找您的 CompanyNames 列表和 LocationNames 之间的关系。


更新

没有公司名称列表,我必须从代​​表多个位置的最具描述性或最佳位置名称生成公司名称。

好的...试试这个:

  1. 通过查找由大部分或全部字母字符组成的 LocationNames 来构建候选 CompanyNames 列表。您可以为此使用正则表达式。将此列表存储在单独的表中。
  2. 按字母顺序对该列表进行排序并(手动)确定哪些条目应该是 CompanyNames。
  3. 将每个 CompanyName 与每个 LocationName 进行比较并得出匹配分数(使用Levenshtein或其他一些字符串匹配算法)。将结果存储在单独的表中。
  4. 设置阈值分数,使得任何 MatchScore < Threshold 都不会被视为与给定 CompanyName 匹配。
  5. 通过 CompanyName | 手动审查 LocationNames 位置名称 | MatchScore,并找出哪些是真正匹配的。通过 MatchScore 排序应该可以减少过程中的痛苦。

上述操作的全部目的是使零件自动化并限制问题的范围。它远非完美,但有望为您省去手动浏览 18K 记录的麻烦。

于 2008-08-08T16:41:29.623 回答
0

我打算推荐一些复杂的令牌匹配算法,但要正确处理真的很棘手,如果你的数据没有很多相关性(错别字等),那么它不会给出很好的结果。

我建议您向Amazon Mechanical Turk提​​交一份工作,然后让人工进行整理。

于 2008-08-08T16:44:48.480 回答
0

理想情况下,您可能需要一个名为 Company 的单独表,然后在此“Location”表中创建一个 company_id 列,该列是 Company 表主键的外键,可能称为 id。这将避免此表中的大量文本重复(超过 18,000 行,整数外键将在 varchar 列上节省相当多的空间)。

但是您仍然面临着一种方法来加载该 Company 表,然后将其与 Location 中的行正确关联。没有通用的解决方案,但您可以按照以下方式做一些事情:

  1. 创建 Company 表,其中 id 列自动递增(取决于您的 RDBMS)。
  2. 找到所有唯一的公司名称并将它们插入公司。
  3. 将列 company_id 添加到接受 NULL(目前)并且是 Company.id 列的外键的 Location 中。
  4. 对于 Location 中的每一行,确定相应的公司,并使用该公司的 id 更新该行的 company_id 列。这可能是最具挑战性的一步。如果您的数据与示例中显示的一样,您可能需要使用各种字符串匹配方法进行多次运行。
  5. 一旦 Location 中的所有行都具有 company_id 值,那么您可以 ALTER Company 表以向 company_id 列添加 NOT NULL 约束(假设每个位置都必须有一个公司,这似乎是合理的)。

如果可以复制 Location 表,则可以逐步构建一系列 SQL 语句来填充 company_id 外键。如果你犯了一个错误,你可以重新开始并重新运行脚本直到失败。

于 2008-08-08T16:47:35.853 回答
0

是的,我上一篇文章中的第 4 步非常棒。

无论如何,您可能必须手动完成其中的一些工作,但您可能能够将大部分工作自动化。对于您提供的示例位置,如下查询将设置适当的 company_id 值:

UPDATE  Location
SET     Company_ID = 1
WHERE   (LOWER(Location_Name) LIKE '%to_n shop%'
OR      LOWER(Location_Name) LIKE '%tts%')
AND     Company_ID IS NULL;

我相信这将与您的示例相匹配(我添加了IS NULL不覆盖先前设置的 Company_ID 值的部分),但当然,在 18,000 行中,您必须非常有创意才能处理各种组合。

其他可能有帮助的方法是使用 Company 中的名称来生成上述查询。您可以执行以下操作(在 MySQL 中):

SELECT  CONCAT('UPDATE Location SET Company_ID = ',
        Company_ID, ' WHERE LOWER(Location_Name) LIKE ',
        LOWER(REPLACE(Company_Name), ' ', '%'), ' AND Company_ID IS NULL;')
FROM    Company;

然后只需运行它产生的语句。这可以为你做很多垃圾工作。

于 2008-08-08T22:07:02.527 回答