在2000万篇文章中找到200,000个产品名称的有效方法?

时间:2014-02-18 09:31:49

标签: mysql indexing elasticsearch faceted-search named-entity-recognition

我们有两个(MySQL)数据库,一个拥有约200,000个产品(如“Samsung Galaxy S4”,db-size 200 MB),另一个拥有约1000万篇文章(纯文本,db-size 20GB),可以包含零,产品数据库中的一个或多个产品名称。现在,我们希望在文章文本中找到产品名称,并将它们存储为文章的各个方面,同时在elasticsearch中对其进行索引。使用正则表达式来查找产品非常慢,我们查看了Apache OpenNLP和Stanford Named Entity Recognizer,因为我们必须训练自己的模型,并且github上有一些项目用于将这些NER工具集成到elasticsearch中,但他们不会似乎已经准备好投入生产了。

每天都会添加产品和文章,因此我们必须每天都进行完整的认可。 NER是否可行?还是其他任何想法?我们不必理解文本的语法等,我们只需要尽快找到产品名称字符串。我们不能实时进行计算,因为这样会减慢,所以我们必须预先计算文章和产品之间的连接并将它们存储为方面,这样我们就可以在应用程序中快速查询它们。

那么您建议在如此多的文章中找到这么多产品名称?

2 个答案:

答案 0 :(得分:1)

您最常遇到的一个问题是一致性......新文章和新产品名称总是会出现,并且您将遇到“最终一致性”问题。所以我想到有三种方法可以解决这类问题。

  1. 根据建议,在MySQL中使用全文搜索,基本上在您的产品表上创建一个循环,并为每个产品名称执行MATCH AGAIST查询并将productkey和article键插入到tie表中。这很快,我曾经在SQL Server中运行一个系统,在1B句子中搜索了超过90000个项目。如果你有一个多线程的java程序,它可以分类并完成全文查询,那么你可能会对它的速度感到惊讶。此外,这可能会破坏您的数据库服务器。

  2. 使用正则表达式。将所有产品放在内存中的集合中,正则表达式针对每个文档查找该列表。如果您的文档类似于hadoop,可以并行化,这可以很快。您可以在晚上运行该作业,并将其填充到MySQL表中......这种方法意味着您必须开始将文档存储在HDFS或某些NOSQL解决方案中,或者从MySQL导入到每天的hadoop等等。

  3. 您可以尝试“在索引时”执行此操作,因此当在ElasticSearch中对记录编制索引时,将会进行提取并构建您的构面。我只使用SOLR来做这样的事情......这里的问题是,当你添加新产品时,无论如何都必须再次批处理,因为以前的索引文档不会从中提取新产品。

  4. 因此可能有更好的选择,但是无限扩展的选项(如果你能负担得起的机器)是选项2 ... hadoop工作....但这意味着大的改变。

    这些只是我的想法,所以我希望其他人提出更聪明的想法

    编辑: 至于使用NER,我已经广泛使用了NER,主要是OpenNLP,问题在于它提取的内容不会被标准化,换句话说,它可能会提取产品名称的部分和部分,你会留下处理模糊字符串匹配之类的东西,将NER结果与产品表对齐。 OpenNLP 1.6 trunk有一个名为EntityLinker的组件,它是为这类事物设计的(将NER结果链接到权威数据库)。此外,NER / NLP无法解决一致性问题,因为每次更改NER模型时,都必须重新处理。

答案 1 :(得分:1)

我建议预处理步骤:标记化。如果您对产品列表和传入文章执行此操作,则不需要进行每个产品的搜索:产品列表将是一个自动机,其中每个转换都是给定的标记。

这为我们提供了trie,您可以使用它来匹配产品与文字,搜索结果如下:

products = []
availableNodes = dictionary.root
foreach token in text:
    foreach node in availableNodes:
        if node.productName:
            products.append(node.productName)
    nextAvailableNodes = [dictionary.root]
    foreach node in availableNodes:
        childNode = node.getChildren(token)
        if childNode:
            nextAvailableNodes.append(childNode)
    availableNodes = nextAvailableNodes

据我所知,这个算法非常有效,它允许你微调node.getChildren()函数(例如解决大写或变音符号问题)。将产品列表加载为trie可能需要一些时间,在这种情况下,您可以将其缓存为二进制文件。

这个简单的方法可以使用Hadoop或其他MapReduce方法轻松分发,可以通过文本或产品列表进行分发,例如参见this article(但您可能需要更新/更准确的方法)。