簡體   English   中英

如何找到mySQL行之間的相似性?

[英]How to find similarity between mySQL rows?

我正在嘗試創建一個腳本,在我的表行之間找到匹配的百分比。 例如,表產品中的mySQL數據庫包含字段名稱 (索引,FULLTEXT),其值為

LG 50PK350 PLASMA TV 50" Plasma TV Full HD 600Hz 
LG TV 50PK350 PLASMA 50"
LG S24AW 24000 BTU
Aircondition LG S24AW 24000 BTU Inverter

正如您可能看到他們所有人都有相同的關鍵字。 但第一個名字和第二個名字更相似。 此外,第3和第4關鍵字之間的關鍵字比第1和第2更相似。

我的mySQL DB有數千個產品名稱。 我想要的是找到那些具有超過百分比(比如說60%)相似性的名稱。

例如,正如我所說,第一個,第二個(以及任何其他名稱)在它們之間匹配超過60%,將以組樣式格式回應,讓我知道這些產品是相似的。 第3和第4個以及任何其他超過60%的匹配將在另一組中回顯,告訴我這些產品匹配。

如果可能,那么回顯滿足所有分組匹配名稱的關鍵字將會很棒。 例如, LG S24AW 24000 BTU是包含在第3和第4名稱中的關鍵字。

最后,我將創建所有這些關鍵字的列表。

我現在有以下查詢(如Jitamaro建議)

Select t1.name, t2.name From products t1, products t2

在所有其他名稱旁邊創建一個新名稱字段。 對不起,我不知道如何解釋它,但這就是它的作用:(真正的價值觀是上面的產品名稱)

在查詢之前

-name-
A
B
C
D
E

查詢后

-name- -name-
A        A
B        A
C        A
D        A
E        A
A        B
B        B
C        B
D        B
E        B
.
.
.

有沒有辦法用mySQL或PHP找到匹配的名稱並提取關鍵字,如上所述? 請分享代碼示例。

謝謝社區。

使用LIKE OR REGEXP查詢DB:

SELECT * FROM product WHERE product_name LIKE '%LG%';
SELECT * FROM product WHERE product_name REGEXP "LG";

循環結果並使用similar_text():

$a = "LG 50PK350 PLASMA TV 50\" Plasma TV Full HD 600Hz"; // DB value
$b = "LG TV 50PK350 PLASMA 50\"" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

//outputs: Matched: 21 Percentage: 58.3333333333%

你的第二個例子匹配62.0689655172%:

$a = "LG S24AW 24000 BTU"; // DB value
$b = "Aircondition LG S24AW 24000 BTU Inverter" ; // USER QUERY

$i = similar_text($a, $b, $p);
echo("Matched: $i  Percentage: $p%");

您可以定義高於(比如說40%)的百分比來匹配產品。
請注意,similar_text()是大小寫SensitivE所以你應該小寫字符串。

至於你的第二個問題, levenshtein()函數( 在MySQL中 )將是一個很好的候選者。

當我看你的例子時,我會考慮如何根據標題找到類似的產品。 從你的兩個例子中,我可以看到每一行中有一件事突出其他任何東西:型號。 50PK350可能不會出現在與此模型相關的任何地方。

現在,MySQL本身並不是為處理這樣​​的問題而設計的,而是它上面的一些螺栓連接工具。 部分問題是在所有位置查詢所有這些字段都很昂貴。 你真的想以某種方式拆分它並索引它。 Lucene的相似性類別會對很少出現在所有數據中的單詞給予高分,但確實會顯示為您數據的高百分比。 請參閱Lucene的相似度等級的高級解釋?

你還應該看看全文搜索引擎的比較 - Lucene,Sphinx,Postgresql,MySQL?

根據Lucene相似性類對每個單詞進行評分應該更快,更可靠。 您的分數總和應該為您提供最相關的產品。 對於電視,我希望首先看到完全匹配,然后是其他一些相同尺寸,然后是品牌,一般電視等等。

無論你做什么,都要意識到除非你通過在SQL系統之上使用另一個工具來改變數據結構來創建更好的數據結構,否則你的查詢將會變得太慢而且成本太高。 我認為Lucene可能是要走的路。 未提及的獅身人面像或其他選項也可能需要考慮。

這比看起來更棘手,你的帖子中缺少信息:

  • 人們將如何使用這種自動完成功能?
  • 您是否可以找到產品的所有名稱? 因為顯然並非所有商店都將其產品命名為類似,因此店員可能無法找到他找到的產品。
  • 您是否有關於同一產品的產品名稱的信息?
  • 您正在搜索哪家商店是否相關? 這個自動完成在哪里使用?
  • 自動完成是否真的只建議與您鍵入的所有單詞匹配的產品? (技術上,糾正錯別字並不難)

我認為您需要更清晰地了解您(或更好的用戶)希望此自動完成功能執行的操作。

自動完成功能是一種用戶友好型功能。 它可能以模糊的方式幫助用戶,因此沒有單一的正確答案。 你必須找出最有效的方法,而不是技術上最容易做到的。

首先弄清楚你想要什么,然后擔心技術。

一種可能的解決方案是使用Damerau-Levenstein距離 它可以像這樣使用

select *
from products p
where DamerauLevenstein(p.name, '*user input here*')<=*X*

您必須找出最能滿足您需求的X. 它應該是大於零的整數。 您可以根據需要對其進行硬編碼,參數化或計算。

最棘手的是DamerauLevenstein 它必須是存儲過程,實現Damerau-Levenstein算法。 我這里沒有MySQL,所以我可能會在今天晚些時候為你寫。

更新: MySQL不支持存儲過程中的數組,因此除非在每個函數調用中使用臨時表,否則無法在MySQL中實現Damerau-Levenstein。 這將導致糟糕的表現。 因此,您有兩個選擇:使用像Alix Axel建議的levenstein在PHP中循環結果,或者將數據庫遷移到支持數組的PostgreSQL。 還有一個創建User-Defined函數的選項,但是這需要在C中編寫這個函數,將它鏈接到MySQL並可能重建MySQL,所以這樣你只會增加更多頭痛。

這個問題與此類似:):

在SQL中實現子字符串搜索的最佳方法是什么?

Trigram可以很容易地找到類似的行,在那個問題中我發布了一個php + mysql + trigram解決方案

你的方法看似合理。 為了匹配類似的產品,我建議進行三元搜索。 關於它如何與String :: Trigram Perl模塊一起工作,有一個相當不錯的解釋。

我建議使用trigram搜索來獲取匹配列表,也可以根據您需要處理的數據量以及添加新產品的頻率來進行一些人工審核。 我發現這種方法在實踐中運作良好。

也許你想找到2個字符串中最長的公共子串? 然后,您需要為每個字符串計算后綴樹,請參見http://en.wikipedia.org/wiki/Longest_common_substring_problem

如果要相互檢查所有名稱,則需要在mysql中進行交叉連接。 有很多方法可以實現這一目標:

1. Select a, b From t1, t2

2. Select a, b From t1 Join t2

3. Select a, b From t1 Cross Join t2

然后你可以遍歷結果。 當我說用n ^ 2-(n-1)個元素創建一個二維數組並且每個元素相互連接時,這是相同的。

PS:選擇t1.name,t2.name從產品t1,產品t2

看來你可能總想要返回最短的字符串? 這比任何事情都更重要或更具問題。 但是你可能會有......

SELECT * FROM products LIMIT 1
WHERE product_name like '%LG%'
ORDER BY LENGTH(product_name) ASC

這聽起來你已經經歷了所有這些麻煩來解釋一個復雜的場景,然后說你想忽略最佳答案,讓我們給你“握手”協議(一切都與未完成的一切相比)與之相比)。 所以...偽代碼:

select * from table order by id
while (result) {
    select * from table where id > result_id
}

那樣做。

如果您的數據庫只是將UPC代碼作為其中一個字段,並且該字段維護得很好,即您可以相信它是由數據庫維護者正確輸入並正確反映了該項目的內容 - 那么您就不會需要做你建議的所有工作。

一個更好的想法可能是在你的下一個數據庫中有一個UPC字段 - 並將其限制為唯一。

數據庫用戶試圖將已經存在的UPC放入數據庫中 - 它們會出錯。

數據庫保持其完整性。

如果這樣的數據庫保持其完整性 - 做你所建議的必要性永遠不會出現。

這可能對您當前的任務(道歉)沒有多大幫助 - 但對於未來類似的數據庫 - 您可能希望考慮一下......

這是一個聚類問題,可以通過數據挖掘方法解決。 http://en.wikipedia.org/wiki/Cluster_analysis )它需要大量內存和計算密集型操作,不適合數據庫引擎。 否則,將不存在單獨的數據挖掘,文本挖掘或業務分析軟件。

我建議你使用一些全文搜索引擎,比如sphinx 它有可能實現您想要的任何算法。 例如,您可以使用“quorom”或“any”搜索。

您可以使用LIKE在表中查找類似的產品名稱。 例如:

SELECT * FROM product WHERE product_name LIKE 'LG%';

這是另一個想法(但我投票給levenshtein() ):

創建名稱及其頻率中使用的所有單詞的臨時表。

選擇結果范圍(最流行的詞可能是像LCD或LED這樣的詞,大多數獨特的詞可能是好的,它們可能是產品的實際名稱)。

建議每個結果詞:

好吧,我想我試圖實現非常類似的東西。 它可以像谷歌Chrome地址框一樣工作。 當您鍵入地址時,它會為您提供建議。 就我而言,這就是你想要實現的目標。

我不能給你一個確切的解決方案,但一些建議。

  1. 您需要實現下拉框,有人開始輸入他們正在尋找的產品
  2. 然后你需要得到下拉列表的當前值,然后像上面發布的那樣運行查詢。 可以是“SELECT * FROM product WHERE product_name LIKE'LG%';”
  3. 保存查詢結果
  4. 刷新頁面
  5. 將查詢結果添加到下拉列表中

注意:

您需要將查詢結果保存在某個地方,例如帶有HTML代碼的文本文件,即“選項”LG TS 600“/ option”(當然,將<>括號添加到選項中)。 頁面刷新后,此值將用於填充選項框。 您需要為用戶設置用戶會話以獲得相同用戶的相同結果,否則如果更多用戶同時使用搜索,則可能會發生沖突。 因此,使用搜索ID和會話ID,您可以匹配它們。 您可以將其保存在文件或表中。 表會更方便。 實際上,在我看來,整個子系統都是你在尋找什么。

我希望它有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM