2017-11-11 145 views
1

嘗試爲我的CMS設計索引和搜索系統。PHP和MySql索引上的最佳文本搜索邏輯

我做了什麼到現在是:在數據庫表

三列(POST表)(InnoDB的 - utf8mb4_unicode_ci)。

  1. 原始內容(JSON格式)。

  2. 令牌(充分利用JSON的所有文字,刪除停用詞,然後保存令牌此列),也使該列的索引。

  3. 令牌(直接從一個標記字段來,計算器等標記。),也索引該字段。

我的CMS正在研究這種方法,但由於從原始內容生成的令牌增加了索引和表大小。

有螞蟻的方法來改善嗎?

我來自JAVA背景(正在使用盧卡恩)。對我來說,製作一個所有停用詞典的字典很難。如果有人知道預先製作的API操作系統腳本以消除停用詞。

+0

請問[全文搜索](https://dev.mysql.com/doc/refman/5.7/en/fulltext-search.html)有效嗎? –

+0

@AlonEitan似乎不錯,也支持停用詞刪除,但我仍然使用第二列,因爲第一列包含JSON鍵,這不利於索引, –

+0

使用具有唯一標記的單獨表格,並將其橋接到主表格多對多的關係。這樣你可以規範化你的數據,並減少它的大小。它還使搜索標籤變得更容易,然後您可以使用IN,而不是Match Match或通配符,因此您可以充分利用索引。它也有助於在標籤搜索字段等創建類似自動完成的東西。 – ArtisticPhoenix

回答

1

對於tag系統,如堆棧溢出或許多其他系統,我會用3個表。

  • 的主表與JSON
  • 一個標籤表
  • 路口或橋臺爲多對多的關係。

使用單獨的標籤表,您可以使用IN=進行搜索。您可以使用該表作爲自動完成。你「正常化」你的數據,減少它。等等......它確實爲查詢增加了一些聯接和一些複雜性,但我認爲它仍然相當微不足道。

此外,我已經在Jquery中編寫了一個文本輸入插件來識別文本字段中的標籤。它很大程度上沒有記錄,但歡迎您隨時隨地使用它。

https://github.com/ArtisticPhoenix/jQuery-Plugins/tree/master/jQuery-Plugins/jqWall

這對我們需要一個「推特」喜歡用#標籤牆上的一個小項目,所以它可以設置爲識別並自動完成作爲與#例如啓動一個用戶類型的標籤。允許用戶使用標籤自動完成文本並減少錯誤或拼寫錯誤發生。你可以定義你想要匹配的東西,並且對其他功能有一些回調。使用起來非常簡單。

您可以在此看到小提琴的基本設置(這是很標準的多對多)

https://www.db-fiddle.com/f/2WSaLjtnuDrZE2CcVhAe9S/1

一些其他功能這給你的是例如此查詢。

SELECT 
    t.* 
FROM 
    tags AS t 
LEFT JOIN 
    posts_tags AS pt ON t.id = pt.tag_id 
WHERE 
    pt.tag_id IS NULL; 

這將選擇所有未在帖子中使用的標籤。除了計算有多少帖子具有給定標籤也很容易。

SELECT 
    count(p.id) AS total 
FROM 
    posts AS p 
JOIN 
    posts_tags AS pt ON p.id = pt.post_id 
JOIN 
    tags AS t ON pt.tag_id = t.id 
WHERE 
    tag = 'Programming'; 

這可能看起來很複雜,如果你不習慣像這樣的關係如何工作和使用連接。但是當你有一個關鍵字列表時,考慮統計有多少帖子。您將使用keywords LIKE '%Java%',它可能會損害您的性能(無論何時使用%word前面的通配符)。另外值得注意的是,如果你有像Javascript這樣的關鍵字,你會用這個查詢來計算它,而Java根本不像Javascript,因此使用部分字符串匹配精確計算你有多少帖子是不可能的。

我建議的唯一的方法是如果你使用單個字段去使用分隔符,並將其包含在內容的前面和後面,就像這樣。

|tag1|tag2|tag|tag10| 

這樣做的原因是,那麼你可以包括在你的搜索分隔符,認爲這部分查詢

WHERE tag LIKE "%tag%" 

現在,如果你搜索,你會發現所有的標籤,而是因爲我們有我們的分隔符,你可以這樣做

WHERE tag LIKE "%|tag|%" 

這會限制匹配。但爲了使其工作,您需要在列表的開始和結束處使用分隔符。考慮這個tag1|tag10|tag沒有那些我們不能匹配|tag|%|tag|%所以這一切都崩潰了。對於具有輕量用途的系統,這可能會工作ok,但由於索引的性質以及它們如何處理通配符搜索,單獨的表格仍然優越。

console.log("type any of these 'Java', 'JavaScript', 'Programming', 'PHP' and press enter to select from list, or use the mouse."); 
 
console.log("press enter to simulate submission, logs contents."); 
 

 
$('#test').jqWall({ 
 
    id: 'jqWall', 
 
    autoComplete: { 
 
    cache: ['Java', 'JavaScript', 'Programming', 'PHP'], 
 
    match: /([^\s]+)$/, //$ ends with is required 
 
    search : function(term, matches, callback){ 
 
     if(matches.lenght == 0){ 
 
     //get matches array from server by AJAX using `term` 
 
     } 
 
     callback(matches); //requred 
 
    
 
     }, 
 
    }, 
 
    submit : function(wrapper){ 
 
    //press enter to submit 
 
    var contents = wrapper.find('textarea').val(); 
 
    //you could post contents back to server to save. 
 
    console.log(contents); 
 
    } 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://rawgit.com/ArtisticPhoenix/jQuery-Plugins/master/jQuery-Plugins/jqWall/jqWall.js"></script> 
 
<link href="https://rawgit.com/ArtisticPhoenix/jQuery-Plugins/master/jQuery-Plugins/jqWall/jqWall.css" rel="stylesheet" /> 
 
<style type="text/css"> 
 
    #jqWall textarea { 
 
    width: 400px; 
 
    height: 200px; 
 
    } 
 
</style> 
 

 

 
<div id="test" style=""></div>

+0

我對標籤使用了相同的方法,但根據您的要求,twist是從輸入的帖子文本中編輯標籤。之後將不需要索引完整的POST(全文索引功能)。我對嗎? –

+0

這將是很難使用您的非文檔代碼,通過分析過程PLZ指南。比如不推薦停用詞和無用詞,只推薦有用的詞和重量詞 –

+0

這是正確的,你不必做全文索引。如果你允許他們在文本的主體中,我會使用'#'或類似的。如果你想在主體上搜索,那麼我會使用全文。 – ArtisticPhoenix

0

你所描述的兩個「標記」列的方式,你需要對每一個FULLTEXT指標。然後使用MATCH(token1) AGAINST('+mysql +index IN BOOLEAN MODE)來查找一篇關於「mysql」和「index」(或索引或​​索引或索引等)的帖子。