1

我們有兩個(MySQL)數據庫,其中一個大約有200.000個產品(如「Samsung Galaxy S4」,db-size 200 MB),另一個大約有1000萬篇文章(純文本,db大小20GB)產品數據庫中的一個或多個產品名稱。現在,我們希望在文章文本中查找產品名稱,並將它們存儲爲文章的各個面,同時將它們在elasticsearch中編入索引。使用正則表達式來查找產品非常緩慢,我們考慮了Apache OpenNLP和Stanford命名實體識別器,因爲我們都需要訓練自己的模型,並且在github上有一些項目將這些NER工具集成到elasticsearch中,似乎已經準備好用於生產用途。在2000萬篇文章中找到200,000個產品名稱的有效方法?

產品和文章每天都在添加,所以我們必須每天運行一次完整的認證。 NER是否要走?還是其他想法?我們不必瞭解文本的語法等,我們只需要儘可能快地找到產品名稱字符串。我們無法實時進行計算,因爲這種方法會變慢,所以我們必須預先計算物品和產品之間的連接並將它們存儲爲小平面,因此我們可以在應用程序中快速查詢它們。

那麼,你有什麼建議在如此多的文章中找到如此多的產品名稱?

+0

你可以嘗試使用布爾全文搜索,肯定它會更快:https://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html – Stephan

+0

什麼樣的更快任務?在elasticsearch中建立索引時,我們需要爲每篇文章找到所有匹配的產品。所以如果我們建立一個完整的索引,我們必須在所有2000萬篇文章中搜索所有200,000個產品名稱。在文章中使用「MATCH AGAINST」查詢產品名稱可能是一種選擇,但不會使用elasticsearch在這裏更好?那些在RAM中完全運行的東西呢? – ak2

回答

1

您最常遇到的問題之一就是一致性......新的文章和新的產品名稱總是出現,您將會遇到「最終一致性」問題。所以我想到了三種方法,我已經習慣瞭解決這類問題。

  1. 至於建議,在MySQL中使用全文搜索,基本上建立了自己的產品表中的循環,併爲每個產品的名稱做了MATCH安劍錚,卓傑查詢和插入的ProductKey,和本文重點成平手錶。這很快,我曾經在SQL Server上運行一個系統,其中超過90000個項目正在用1B語句進行搜索。如果你有一個多線程的java程序來分類並且執行完整的文本查詢,你可能會覺得這將是多麼快。此外,這可以錘擊您的數據庫服務器。

  2. 使用正則表達式。將所有產品放在內存中的一個集合中,正則表達式根據每個文檔的列表查找。如果你有像hadoop這樣的文檔,它可以被並行化,這可以很快。你可以在晚上運行這個工作,並讓它填充一個MySQL表...這種方法意味着你將不得不開始將文檔存儲在HDFS或一些NOSQL解決方案中,或者從MySQL導入到hadoop日常等等。

  3. 您可以嘗試「在索引時間」這樣做,所以當記錄在ElasticSearch中索引時,提取將會發生,然後將構建您的構面。我只用SOLR來處理這樣的問題......這裏的問題是,當你添加新產品時,你將不得不再次批處理,因爲以前的索引文檔不會有從它們中提取的新產品。

因此可能會有更好的選擇,但無限擴展的選項是選項2 ...... hadoop工作......但這意味着巨大的變化。

這些只是我的想法,所以我希望其他人想出更聰明的想法

編輯: 至於使用NER,我已經使用NER廣泛,主要OpenNLP,以及與此有關的問題是什麼提取將不會被標準化,或者換句話說,它可能會提取產品名稱的片斷和部分,並且您將繼續處理模糊字符串匹配等事項,以將NER結果與產品表對齊。 OpenNLP 1。6 trunk有一個名爲EntityLinker的組件,它是爲這種類型的事情設計的(將NER結果鏈接到權威數據庫)。另外,NER/NLP不會解決一致性問題,因爲每次更改NER模型時,都必須重新處理。

+0

我認爲我們必須比較性能,對於只有20GB的數據來說,hadoop集羣可能太多了,但我們對想法持開放態度。我想我們會嘗試查詢mysql和elasticsearch本身。所以你使用多個線程並行查詢一個大的mysql全文索引?將索引/數據加載到ram/ramdisk上沒有意義嗎? – ak2

+1

我同意hadoop可能會矯枉過正,這取決於你的doc增長率。關於文本索引的好處是您可以執行如下操作(僞): (product prod:products){ insert into doc_prod_tie(docid,prodid)從doc匹配的文檔中選擇@prodid,docid(doc.text)反對(@productName在布爾模式下) } 您不需要一次一個地將文檔加載到內存中,您只需一次一個地查看每個產品,並且所有在prods上的命中都將被捕獲用全文查詢進行一組操作。當然,這不是完成它的唯一方法。 – markg

+0

工作得很好,我們唯一的問題是索引速度的MySQL:http://stackoverflow.com/questions/22360657/speed-up-full-text-indexing-mysql – ak2

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()函數(例如,以解決大小寫或變音符號問題)。將產品列表加載爲特里可能需要一些時間,在這種情況下,您可以將其緩存爲二進制文件。

這個簡單的方法可以使用Hadoop或其他MapReduce方法輕鬆分發,可以通過文本或產品列表進行分發,例如參見this article(但您可能需要更新/準確的方法)。

+0

是不是已經通過mysql全文搜索完成了標記化? – ak2

相關問題