<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MySQL 模糊查詢再也不用like+%了

          共 11755字,需瀏覽 24分鐘

           ·

          2024-04-13 14:20

          ?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項目實戰(zhàn) / Java 學習路線 / 一對一提問 / 學習打卡 /  贈書福利


          全棧前后端分離博客項目 2.0 版本完結啦, 演示鏈接http://116.62.199.48/ ,新項目正在醞釀中。全程手摸手,后端 + 前端全棧開發(fā),從 0 到 1 講解每個功能點開發(fā)步驟,1v1 答疑,直到項目上線。目前已更新了239小節(jié),累計38w+字,講解圖:1645張,還在持續(xù)爆肝中.. 后續(xù)還會上新更多項目,目標是將Java領域典型的項目都整一波,如秒殺系統(tǒng), 在線商城, IM即時通訊,Spring Cloud Alibaba 等等,戳我加入學習,已有1200+小伙伴加入(早鳥價超低)


          目錄
          • 前言

          • 倒排索引

          • 全文檢索

          • 小結


          前言

          我們都知道 InnoDB 在模糊查詢數據時使用 "%xx" 會導致索引失效,但有時需求就是如此,類似這樣的需求還有很多。

          例如,搜索引擎需要根基用戶數據的關鍵字進行全文查找,電子商務網站需要根據用戶的查詢條件,在可能需要在商品的詳細介紹中進行查找,這些都不是 B+ 樹索引能很好完成的工作。

          通過數值比較,范圍過濾等就可以完成絕大多數我們需要的查詢了。但是,如果希望通過關鍵字的匹配來進行查詢過濾,那么就需要基于相似度的查詢,而不是原來的精確數值比較,全文索引就是為這種場景設計的。

          全文索引(Full-Text Search)是將存儲于數據庫中的整本書或整篇文章中的任意信息查找出來的技術。它可以根據需要獲得全文中有關章、節(jié)、段、句、詞等信息,也可以進行各種統(tǒng)計和分析。

          在早期的 MySQL 中,InnoDB 并不支持全文檢索技術,從 MySQL 5.6 開始,InnoDB 開始支持全文檢索

          倒排索引





          全文檢索通常使用倒排索引(inverted index)來實現,倒排索引同 B+Tree 一樣,也是一種索引結構。它在輔助表中存儲了單詞與單詞自身在一個或多個文檔中所在位置之間的映射。

          這通常利用關聯數組實現,擁有兩種表現形式:

          • inverted file index:{單詞,單詞所在文檔的id}

          • full inverted index:{單詞,(單詞所在文檔的id,再具體文檔中的位置)}

          上圖為 inverted file index 關聯數組,可以看到其中單詞"code"存在于文檔1,4中,這樣存儲再進行全文查詢就簡單了,可以直接根據 Documents 得到包含查詢關鍵字的文檔。

          而 full inverted index 存儲的是對,即(DocumentId,Position),因此其存儲的倒排索引如下圖,如關鍵字"code"存在于文檔 1 的第 6 個單詞和文檔 4 的第 8 個單詞。

          相比之下,full inverted index 占用了更多的空間,但是能更好的定位數據,并擴充一些其他搜索特性。



          全文檢索





          | 創(chuàng)建全文索引

          ①創(chuàng)建表時創(chuàng)建全文索引語法如下:

          CREATE TABLE table_name ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, author VARCHAR(200), 
          title VARCHAR(200), content TEXT(500), FULLTEXT full_index_name (col_name) ) ENGINE=InnoDB;

          輸入查詢語句:

          SELECT table_id, namespace from INFORMATION_SCHEMA.INNODB_TABLES
          WHERE name LIKE 'test/%';

          上述六個索引表構成倒排索引,稱為輔助索引表。當傳入的文檔被標記化時,單個詞與位置信息和關聯的 DOC_ID,根據單詞的第一個字符的字符集排序權重,在六個索引表中對單詞進行完全排序和分區(qū)。

          ②在已創(chuàng)建的表上創(chuàng)建全文索引語法如下:

          CREATE FULLTEXT INDEX full_index_name ON table_name(col_name);

          | 使用全文索引

          MySQL 數據庫支持全文檢索的查詢,全文索引只能在 InnoDB 或 MyISAM 的表上使用,并且只能用于創(chuàng)建 char,varchar,text 類型的列。

          其語法如下:

          MATCH(col1,col2,...) AGAINST(expr[search_modifier])
          search_modifier:
          {
              IN NATURAL LANGUAGE MODE
              | IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
              | IN BOOLEAN MODE
              | WITH QUERY EXPANSION
          }

          全文搜索使用 MATCH() AGAINST() 語法進行,其中,MATCH() 采用逗號分隔的列表,命名要搜索的列。

          AGAINST() 接收一個要搜索的字符串,以及一個要執(zhí)行的搜索類型的可選修飾符。全文檢索分為三種類型:自然語言搜索、布爾搜索、查詢擴展搜索,下面將對各種查詢模式進行介紹。

          Natural Language

          自然語言搜索將搜索字符串解釋為自然人類語言中的短語,MATCH() 默認采用 Natural Language 模式,其表示查詢帶有指定關鍵字的文檔。

          接下來結合 demo 來更好的理解 Natural Language:

          SELECT
              count(*) AS count 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( 'MySQL' );

          上述語句,查詢 title,body 列中包含 'MySQL' 關鍵字的行數量。上述語句還可以這樣寫:

          SELECT
              count(IF(MATCH ( title, body ) 
              against ( 'MySQL' ), 1NULL )) AS count 
          FROM
              `fts_articles`;

          上述兩種語句雖然得到的結果是一樣的,但從內部運行來看,第二句 SQL 的執(zhí)行速度更快些,因為第一句 SQL(基于 where 索引查詢的方式)還需要進行相關性的排序統(tǒng)計,而第二種方式是不需要的。

          還可以通過 SQL 語句查詢相關性:

          SELECT
              *,
              MATCH ( title, body ) against ( 'MySQL' ) AS Relevance 
          FROM
              fts_articles;

          相關性的計算依據以下四個條件:

          • word 是否在文檔中出現

          • word 在文檔中出現的次數

          • word 在索引列中的數量

          • 多少個文檔包含該 word


          對于 InnoDB 存儲引擎的全文檢索,還需要考慮以下的因素:

          • 查詢的 word 在 stopword 列中,忽略該字符串的查詢

          • 查詢的 word 的字符長度是否在區(qū)間 [innodb_ft_min_token_size,innodb_ft_max_token_size] 內


          如果詞在 stopword 中,則不對該詞進行查詢,如對 'for' 這個詞進行查詢,結果如下所示:

          SELECT
              *,
              MATCH ( title, body ) against ( 'for' ) AS Relevance 
          FROM
              fts_articles;

          可以看到,'for'雖然在文檔 2,4 中出現,但由于其是 stopword,故其相關性為 0。

          參數 innodb_ft_min_token_size 和 innodb_ft_max_token_size 控制 InnoDB 引擎查詢字符的長度。

          當長度小于 innodb_ft_min_token_size 或者長度大于 innodb_ft_max_token_size 時,會忽略該詞的搜索。

          在 InnoDB 引擎中,參數 innodb_ft_min_token_size 的默認值是 3,innodb_ft_max_token_size 的默認值是 84。

          Boolean

          布爾搜索使用特殊查詢語言的規(guī)則來解釋搜索字符串,該字符串包含要搜索的詞,它還可以包含指定要求的運算符,例如匹配行中必須存在或不存在某個詞,或者它的權重應高于或低于通常情況。

          例如,下面的語句要求查詢有字符串"Pease"但沒有"hot"的文檔,其中+和-分別表示單詞必須存在,或者一定不存在。

          select * from fts_test where MATCH(content) AGAINST('+Pease -hot' IN BOOLEAN MODE);

          Boolean 全文檢索支持的類型包括:

          • +:表示該 word 必須存在

          • -:表示該 word 必須不存在

          • (no operator):表示該 word 是可選的,但是如果出現,其相關性會更高

          • @distance:表示查詢的多個單詞之間的距離是否在 distance 之內,distance 的單位是字節(jié),這種全文檢索的查詢也稱為 Proximity Search,如 MATCH(context) AGAINST('"Pease hot"@30' IN BOOLEAN MODE)語句表示字符串 Pease 和 hot 之間的距離需在 30 字節(jié)內

          • >:表示出現該單詞時增加相關性

          • <:表示出現該單詞時降低相關性

          • ~:表示允許出現該單詞,但出現時相關性為負

          • * :表示以該單詞開頭的單詞,如 lik*,表示可以是 lik,like,likes

          • " :表示短語


          下面是一些 demo,看看 Boolean Mode 是如何使用的。

          demo1:+ -

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( '+MySQL -YourSQL' IN BOOLEAN MODE );

          上述語句,查詢的是包含 'MySQL' 但不包含 'YourSQL' 的信息。

          demo2:no operator

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( 'MySQL IBM' IN BOOLEAN MODE );

          上述語句,查詢的 'MySQL IBM' 沒有 '+','-'的標識,代表 word 是可選的,如果出現,其相關性會更高。

          demo3:@

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( '"DB2 IBM"@3' IN BOOLEAN MODE );


          上述語句,代表 "DB2" ,"IBM"兩個詞之間的距離在 3 字節(jié)之內。

          demo4:> <

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( '+MySQL +(>database <DBMS)' IN BOOLEAN MODE );

          上述語句,查詢同時包含 'MySQL','database','DBMS' 的行信息,但不包含'DBMS'的行的相關性高于包含'DBMS'的行。

          demo5: ~

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( 'MySQL ~database' IN BOOLEAN MODE );

          上述語句,查詢包含 'MySQL' 的行,但如果該行同時包含 'database',則降低相關性。

          demo6:*

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( 'My*' IN BOOLEAN MODE );

          上述語句,查詢關鍵字中包含'My'的行信息。

          demo7:"

          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH ( title, body ) AGAINST ( '"MySQL Security"' IN BOOLEAN MODE );

          上述語句,查詢包含確切短語 'MySQL Security' 的行信息。

          Query Expansion

          查詢擴展搜索是對自然語言搜索的修改,這種查詢通常在查詢的關鍵詞太短,用戶需要 implied knowledge(隱含知識)時進行。

          例如,對于單詞 database 的查詢,用戶可能希望查詢的不僅僅是包含 database 的文檔,可能還指那些包含 MySQL、Oracle、RDBMS 的單詞,而這時可以使用 Query Expansion 模式來開啟全文檢索的 implied knowledge。

          通過在查詢語句中添加 WITH QUERY EXPANSION / IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 可以開啟 blind query expansion(又稱為 automatic relevance feedback)。

          該查詢分為兩個階段:

          • 第一階段:根據搜索的單詞進行全文索引查詢

          • 第二階段:根據第一階段產生的分詞再進行一次全文檢索的查詢


          接著來看一個例子,看看 Query Expansion 是如何使用的。

          -- 創(chuàng)建索引
          create FULLTEXT INDEX title_body_index on fts_articles(title,body);
          -- 使用 Natural Language 模式查詢
          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH(title,body) AGAINST('database');

          使用 Query Expansion 前查詢結果如下:

          -- 當使用 Query Expansion 模式查詢
          SELECT
              * 
          FROM
              `fts_articles` 
          WHERE
              MATCH(title,body) AGAINST('database' WITH QUERY expansion);

          使用 Query Expansion 后查詢結果如下:

          由于 Query Expansion 的全文檢索可能帶來許多非相關性的查詢,因此在使用時,用戶可能需要非常謹慎。

          | 刪除全文索引

          ①直接刪除全文索引語法如下:

          DROP INDEX full_idx_name ON db_name.table_name;

          ②使用 alter table 刪除全文索引語法如下:

          ALTER TABLE db_name.table_name DROP INDEX full_idx_name;


          小結





          本文從理論與實踐結合的角度對 fulltext index 做了介紹。InnoDB 的全文檢索在一些簡單的搜索場景下還是比較實用的,可以替代 like+%,并且不需要額外依賴其他服務。復雜搜索場景的話,我們還是需要使用 ES 這類搜索引擎。

          ?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項目實戰(zhàn) / Java 學習路線 / 一對一提問 / 學習打卡 /  贈書福利


          全棧前后端分離博客項目 2.0 版本完結啦, 演示鏈接http://116.62.199.48/ ,新項目正在醞釀中。全程手摸手,后端 + 前端全棧開發(fā),從 0 到 1 講解每個功能點開發(fā)步驟,1v1 答疑,直到項目上線。目前已更新了239小節(jié),累計38w+字,講解圖:1645張,還在持續(xù)爆肝中.. 后續(xù)還會上新更多項目,目標是將Java領域典型的項目都整一波,如秒殺系統(tǒng), 在線商城, IM即時通訊,Spring Cloud Alibaba 等等,戳我加入學習,已有1200+小伙伴加入(早鳥價超低)



              
                 

          1. 我的私密學習小圈子~

          2. 騰訊二面:@Bean 與 @Component 用在同一個類上,會怎么樣?

          3. 提高系統(tǒng)吞吐量的一把利器:DeferredResult 到底有多強?

          4. 面試官:單核 CPU 支持 Java 多線程嗎?為什么?被問懵了!

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數據庫、數據結構等等。

          獲取方式:點“在看”,關注公眾號并回復 Java 領取,更多內容陸續(xù)奉上。

          PS:因公眾號平臺更改了推送規(guī)則,如果不想錯過內容,記得讀完點一下在看,加個星標,這樣每次新文章推送才會第一時間出現在你的訂閱列表里。

          “在看”支持小哈呀,謝謝啦

          瀏覽 159
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜桃av久久久亚洲精品 | 天堂网在线视频免费观看 | 亚洲欧洲色| 亚洲精品一区二区无码日本蜜桃 | 日韩~欧美~中文字幕 |