Sphinx查詢效能非常厲害,億級資料下輸入關鍵字,大部分能在0.01~0.1秒,少部分再5秒之內查出資料。
Sphinx
- 官方文件:http://sphinxsearch.com/docs/sphinx3.html
- 極簡概括:
由C++編寫的高效能全文搜尋引擎的開源元件,C/S架構,跨平臺(支援Linux、Windows、MacOS),支援分散式部署,並可直接適配MySQL。 - 解決問題:
因為MySQL的 like %keyword% 不走索引,且全文索引不支援中文,所以需要藉助其它元件。適用於不經常更新的資料的全文搜尋。 - 同類產品:
ElasticSearch、Solr、Lucene、Algolia、XunSearch。 - 使用思路:
傳送給Sphinx關鍵字,然後Sphinx返回id給PHP,PHP再呼叫MySQL根據id查詢。也就是幫著MySQL找id的,MySQL走主鍵索引,查詢效能很高。 - API支援:
Sphinx附帶了三種不同的API,SphinxAPI、SphinxSE和SphinxQL。SphinxAPI是一個可用於Java、PHP、Python、Perl、C和其他語言的原生庫。SphinxSE是MySQL的一個可插拔儲存引擎,支援將大量結果集直接傳送到MySQL伺服器進行後期處理。SphinxQL允許應用程式使用標準MySQL客戶端庫和查詢語法查詢Sphinx。 - SQL擴充套件
Sphinx不僅限於關鍵字搜尋。在全文搜尋結果集之上,您可以計算任意算術表示式、新增WHERE條件、排序依據、分組依據、使用最小值/最大值/AVG值/總和、聚合等。本質上,支援成熟的SQL SELECT。
建表
CREATE TABLE `articles` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(16000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=320974 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
億級大資料來源準備
- 決策分析:
億級的資料量,還都得是中文,如果是52個大小寫字母和10個數字可以隨機,中文隨機效果差,最好是有能閱讀通暢的資料來源,而不是隨機漢字資料來源。 - 嘗試尋找:
嘗試看了txt版的《三國演義》,發現行數太少,所以轉變思維,更大的資料量,只能是長篇小說,翻看了最長的小說,也才22萬行,1行小說對應1條MySQL資料,資料量還是太少,雖然迴圈小說內容插入也行,但還是差點意思。 - 資源整合:
程式設計師天天玩的就是資料,這點小事難不倒我,去網盤找txt小說資源合集https://www.aliyundrive.com/s/LBBg4ZvWip2/folder/63a138e95845afd3baa947db96342937033c254f
找到了如下35000本txt的小說。 - 資料合併:
下載了幾千個txt小說,需要用命令把這些合併成一個檔案,使用cat * > all.txt
方便PHP程式逐行讀取。整合後的單個txt檔案9.57個G。 - 資料入庫:
大資料檔案一次載入會把記憶體撐爆,所以需要使用yield 生成(迭代)器
去逐行讀取檔案。
set_time_limit(0);
$file = 'C:/Users/Administrator/Desktop/all.txt';
/**
* @function 逐行讀取大檔案
* @param $file_name string 檔名
* @return Generator|object
*/
function readLargeFile($file_name) {
$file = fopen($file_name, 'rb');
if (! $file) {
return false;
}
while (! feof($file)) {
$line = fgets($file);
if ($line !== false) {
yield $line;
}
}
fclose($file);
}
// 使用生成器逐行讀取大檔案
$file_resource = readLargeFile($file);
if(! $file_resource) {
echo '檔案讀取錯誤';
die;
}
$db = \Illuminate\Support\Facades\DB::table('articles');
$arr = [];
foreach ($file_resource as $line) {
//獲取單行編碼
$from_charset = mb_detect_encoding($line, 'UTF-8, GBK, GB2312, BIG5, CP936, ASCII');
//轉碼操作,因為有些是ANSI,GBK的編碼,最好轉換成UTF-8
$utf8_str = @iconv($from_charset, 'UTF-8', $line);
//遇見空行,直接過濾
if(in_array($utf8_str, ["\n", "\r", "\n\r", "\r\n"])) {
continue;
}
$arr[] = ['content' => $utf8_str];
if(count($arr) >= 10000) {
$db->insert($arr);
$arr = [];
}
}
-
效能調優:
MyISAM引擎:
insert 發現1秒才1400行的插入速度,不行得調整。
改為批次插入,一次性插入10000行資料,並修改/etc/my.cnf 裡面的max_allowed_packet,將1M改為512M
。
最佳化後,每秒2萬的插入速度。如果是InnoDB引擎
可以調整redo log 刷盤策略,set global innodb_flush_log_at_trx_commit=0
。
並新增緩衝池innodb_buffer_pool_size大小為系統總記憶體的70%
。
把max_allowed_packet,將1M改為512M
,就行了。 -
數量檢查:
兩萬年後,用SELECT count(*) FROM articles
一看,資料量109 450 000,搞定。 -
效能測試:
SELECT count(*) FROM articles where content like '%晴空萬里%',找出來了1931個,花了242秒。
編譯安裝並配置Sphinx Server
虛擬機器裡的CentOS,記得要足夠的空間,用來儲存資料
一個億的資料佔了系統很大空間,系統儲存空間所剩無幾了,/usr/local地方沒地方存,所以把Sphinx放到了/home下,因為/dev/mapper/centos-home掛載到了/home下。
可以事先安裝mmsge
wget https://files.cnblogs.com/files/JesseLucky/coreseek-4.1-beta.tar.gz
tar zxf coreseek-4.1-beta.tar.gz
cd /home/coreseek-4.1-beta/mmseg-3.2.14
./bootstrap
./configure --prefix=/home/mmseg
make && make install
然後安裝Sphinx
cd /home/coreseek-4.1-beta/csft-4.1
./buildconf.sh
發現報錯,不著急
automake: warnings are treated as errors
/usr/share/automake-1.13/am/library.am: warning: 'libstemmer.a': linking libraries using a non-POSIX
/usr/share/automake-1.13/am/library.am: archiver requires 'AM_PROG_AR' in 'configure.ac'
libstemmer_c/Makefile.am:2: while processing library 'libstemmer.a'
/usr/share/automake-1.13/am/library.am: warning: 'libsphinx.a': linking libraries using a non-POSIX
/usr/share/automake-1.13/am/library.am: archiver requires 'AM_PROG_AR' in 'configure.ac'
src/Makefile.am:14: while processing library 'libsphinx.a'
vim ./configure.ac +62
再AC_PROG_RANLIB的下方新增AM_PROG_AR
再次執行./buildconf.sh
發現有如下報錯:
configure.ac:231: the top level
configure.ac:62: error: required file 'config/ar-lib' not found
configure.ac:62: 'automake --add-missing' can install 'ar-lib'
vim buildconf.sh +5
把--foreign改成--add-missing
再次執行./buildconf.sh
直到configure檔案出現。
./configure --prefix=/home/coreseek --with-mysql=/usr/local/mysql --with-mmseg=/home/mmseg --with-mmseg-includes=/home/mmseg/include/mmseg/ --with-mmseg-libs=/home/mmseg/lib/
make && make install
若發現報錯:有ExprEval字樣
vim /home/coreseek-4.1-beta/csft-4.1/src/sphinxexpr.cpp
將所有的
T val = ExprEval ( this->m_pArg, tMatch );
替換為
T val = this->ExprEval ( this->m_pArg, tMatch );
再次執行make,發現還報錯
/home/coreseek-4.1-beta/csft-4.1/src/sphinx.cpp:22292:對‘libiconv_open’未定義的引用
/home/coreseek-4.1-beta/csft-4.1/src/sphinx.cpp:22310:對‘libiconv’未定義的引用
/home/coreseek-4.1-beta/csft-4.1/src/sphinx.cpp:22316:對‘libiconv_close’未定義的引用
vim /home/coreseek-4.1-beta/csft-4.1/src/Makefile +249
把
LIBS = -ldl -lm -lz -lexpat -L/usr/local/lib -lrt -lpthread
改成
LIBS = -ldl -lm -lz -lexpat -liconv -L/usr/local/lib -lrt -lpthread
make && make install
成功安裝
裝好之後配置它,漢字是提示,記得執行環境要刪掉
cd /home/coreseek/etc
記得這個名字一定得是csft.conf,換成其它的也行,但是到後期增量索引合併時會報錯
cp sphinx-min.conf.dist csft.conf
配置內容就是有漢字的地方
vim csft.conf
source articles 起個名,叫articles
{
type = mysql
sql_host = 資料庫IP
sql_user = 資料庫使用者名稱
sql_pass = 資料庫密碼
sql_db = 資料庫
sql_port = 3306 埠
sql_query_pre = select names utf8mb4 加上這行
sql_query = select id,content from articles Sphinx建索引的資料來源
sql_attr_uint = group_id 這行用不上可以去掉
sql_attr_timestamp = date_added 這行用不上可以去掉
sql_query_info_pre = select names utf8mb4 加上這行
sql_query_info = select id,content from articles where id=$id 用Sphinx做什麼SQL的查詢邏輯
#sql_query_post = update sphinx_index_record set max_id = (select max(id) from articles) where table_name = 'articles'; 這個是增量索引要用的東西,這裡暫時用不上,後文會講。
}
index articles 起個名,叫articles
{
source = articles 名字與source一致
path = /home/coreseek/var/data/articles 索引路徑
docinfo = extern 這行用不上可以去掉
charset_dictpath = /home/mmseg/etc 新增這行,表示分詞讀取詞典檔案的位置
charset_type = zh_cn.utf-8 設定字符集編碼
}
儲存並退出,注意資料來源要與索引是一對一的。
然後留意兩個檔案
/home/coreseek/bin/indexer 是用來建立索引的
/home/coreseek/bin/searchd 是啟動服務端程序的。
開啟服務
開啟服務
/home/coreseek/bin/searchd -c /home/coreseek/etc/csft.conf
> ps aux | grep search
root 83205 0.0 0.0 47732 1048 ? S 02:01 0:00 /home/coreseek/bin/searchd -c /home/coreseek/etc/csft.conf
root 83206 0.5 0.0 116968 3728 ? Sl 02:01 0:00 /home/coreseek/bin/searchd -c /home/coreseek/etc/csft.conf
9312埠
> netstat -nlp | grep 9312
tcp 0 0 0.0.0.0:9312 0.0.0.0:* LISTEN 83206/searchd
配置檔案引數說明
https://sphinxsearch.com/docs/current.html#conf-mem-limit
indexer段-----------------------------
mem_limit這是建立索引時所需記憶體,預設32M,可以適當調大,格式如下
mem_limit = 256M
mem_limit = 262144K # same, but in KB
mem_limit = 268435456 # same, but in bytes
https://sphinxsearch.com/docs/current.html#conf-query-log
在searchd段-----------------------------
listen 9312
表示sphinx預設埠
listen=9306
mysql41,表示Sphinx伺服器將監聽在 9306 埠,並使用 MySQL 4.1 協議與客戶端進行通訊。
可以註釋掉以下兩行,使其不記錄日誌
#log = /home/coreseek/var/log/searchd.log
#query_log = /home/coreseek/var/log/query.log
read_timeout
網路客戶端請求讀取超時,以秒為單位。可選,預設為5秒。Searchd將強制關閉未能在此超時時間內傳送查詢的客戶端連線。
max_children
併發搜尋數量,設定為0,表示不限制。
max_matches
引數用於設定每次搜尋操作返回的最大匹配項數
seamless_rotate
在 Sphinx 伺服器配置檔案中,seamless_rotate 引數用於控制索引旋轉操作的行為,確保索引更新過程中的查詢不會被中斷。“旋轉”(rotate)是指在更新索引資料時,將舊的索引檔案替換為新生成的索引檔案的過程。
當設定為 1 或 true(預設值),seamless_rotate 使得 Sphinx 能夠在後臺載入新的索引資料,同時繼續使用舊的索引資料處理查詢請求,直到新的索引完全載入並準備好被使用。這個過程完成後,新的索引將無縫地接管,替換舊的索引,而不會干擾或中斷正在進行的搜尋操作。
如果將 seamless_rotate 設定為 0 或 false,則在索引旋轉時,Sphinx 會暫停處理新的查詢請求,直到新的索引檔案完全載入並準備就緒。這可能會導致短暫的服務中斷,因此,除非有特殊需求,一般建議保持 seamless_rotate 的預設設定(即啟用無縫旋轉),以確保索引更新過程中搜尋服務的連續性和穩定性。
preopen_indexes
是否在啟動時強制預開啟所有索引。可選,預設為1
unlink_old
用於控制在索引旋轉時是否刪除舊的索引檔案。當設定為 1 或 true 時(預設值),舊的索引檔案將被刪除,保持預設值就好。
客戶端配置
PHP SphinxClient手冊:http://docs.php.net/manual/tw/class.sphinxclient.php
cp /home/coreseek-4.1-beta/testpack/api/*.php /test
vim /test/sphinxapi.php
把sphinxapi裡面的SphinxClient()方法改為__construct(),防止稍高版本的PHP,產生類名和方法名一致的通知。
可以先測試,只要返回陣列,就Server和Client都能正常工作。
vim /test/test_coreseek.php
把裡面的網路搜尋改成晴空萬里,把SPH_MATCH_ANY改成SPH_MATCH_PHRASE。
sphinx檔案有個limit選項,這個預設是20,所以最多顯示出20個,可以去修改它。
/usr/local/php5.6/bin/php /test/test_coreseek.php
這是二次改過的test_coreseek.php,對於新手有很友好的提示。
require ( "./sphinxapi.php" );
$search = new SphinxClient ();
//連線Sphinx伺服器
$search->SetServer ( '127.0.0.1', 9312);
//設定超時秒數
$search->SetConnectTimeout ( 3 );
//查詢出來的資料庫ID存放位置
$search->SetArrayResult ( true );
//配置搜尋模式
$search->SetMatchMode (SPH_MATCH_PHRASE);
//分頁,引數1偏移量,從0開始,引數2限制條目
$search->SetLimits(0, 200);
//執行查詢,引數1關鍵字
$res = $search->Query ("黑色衣服", "索引名稱");
if($res === false) {
echo '查詢失敗';
return;
}
//獲取主鍵
$primary_keys = [];
if(! empty($res['matches'])) {
foreach($res['matches'] as $v) {
$primary_keys[] = $v['id'];
}
}
//獲取總數
$all_count = $res['total_found'];
//獲取耗時
$time = $res['time'];
$ids = implode(',', $primary_keys);
echo <<<RESULT
主鍵id: $ids
查詢總數:$all_count
耗時: $time
RESULT;
匹配模式
- 官方文件:https://sphinxsearch.com/docs/current.html#matching-modes
- 呼叫方法:
(new SphinxClient())->SetMatchMode (SPH_MATCH_ALL);
- 分詞舉例:假設關鍵字“白色衣服”,詞語被分成了“白色”和“衣服”。
匹配模式 | 一句話概括 | 會被匹配 | 不會被匹配 |
---|---|---|---|
SPH_MATCH_ALL | 同時包含這些分詞時會被匹配 | 白色的繩子晾著他的衣服 | 他的衣服 |
SPH_MATCH_ANY | 匹配任意一個分詞就行 | 白色的紙 | 白雲 |
SPH_MATCH_PHRASE | 相當於like '%關鍵詞%' | 白色衣服 | 白色的衣服 |
SPH_MATCH_EXTENDED | 支援Sphinx的表示式 | 下方有詳解 | 白色的衣服 |
SPH_MATCH_EXTENDED2 | SPH_MATCH_EXTENDED的別名 | 下方有詳解 | 白色的衣服 |
SPH_MATCH_BOOLEAN | 支援布林方式搜尋 | 下方有詳解 | 白色的衣服 |
SPH_MATCH_FULLSCAN | 強制使用全掃描模式 | 下方有詳解 | 白色的衣服 |
詳解:SPH_MATCH_FULLSCAN
SPH_MATCH_FULLSCAN,強制使用全掃描模式。注意,任何查詢項都將被忽略,這樣過濾器、過濾器範圍和分組仍然會被應用,但不會進行文字匹配。
當滿足以下條件時,將自動啟用SPH_MATCH_FULLSCAN模式來代替指定的匹配模式:
查詢字串為空(即:它的長度是0)。
Docinfo儲存設定為extern。
在完全掃描模式下,所有索引的文件都被認為是匹配的。這樣的查詢仍然會應用過濾器、排序和分組,但不會執行任何全文搜尋。這對於統一全文和非全文搜尋程式碼或解除安裝SQL伺服器很有用(在某些情況下,Sphinx掃描比類似的MySQL查詢執行得更好)。
詳解:SPH_MATCH_BOOLEAN
https://sphinxsearch.com/docs/current.html#boolean-syntax
- kw1|kw2|kw3:或的關係,滿足任意1項即可。
- kw1 -kw2,或者kw1 !kw2:表示!=kw2
詳解:SPH_MATCH_EXTENDED
https://sphinxsearch.com/docs/current.html#extended-syntax
- kw1|kw2|kw3:或的關係,滿足任意1項即可,
- kw1 -kw2,或者kw1 !kw2:表示!=kw2。
- @mysql欄位名 欄位全部內容:匹配某個欄位的內容。
- @* 欄位全部內容:匹配所有欄位的內容。
- ^kw:表示以關鍵字開頭。
- kw$:表示以什麼關鍵字結尾。
實測索引建立效能
- 建立索引
/home/coreseek/bin/indexer -c /home/coreseek/etc/csft.conf articles
,這裡的article就是source段的名稱。 - 伺服器配置:CentOS7.6 16核4G記憶體 固態硬碟。
- Sphinx索引建立速度:36262.76/sec,每條語句大小約10~150個漢字。
- Sphinx索引檔案建立速度:4441931 bytes/sec。
- 一共耗時:1億條資料,建立索引花了50.5分鐘,索引檔案約10個G。
- 原文如下:
Coreseek Fulltext 4.1 [ Sphinx 2.0.2-dev (r2922)]
Copyright (c) 2007-2011,
Beijing Choice Software Technologies Inc (http://www.coreseek.com)
using config file '/home/coreseek/etc/csft.conf'...
indexing index 'articles'...
WARNING: Attribute count is 0: switching to none docinfo
collected 109450000 docs, 13406.8 MB
WARNING: sort_hits: merge_block_size=28 kb too low, increasing mem_limit may improve performance
sorted 3133.8 Mhits, 100.0% done
total 109450000 docs, 13406849231 bytes
total 3018.247 sec, 4441931 bytes/sec, 36262.76 docs/sec
total 322950 reads, 202.304 sec, 27.9 kb/call avg, 0.6 msec/call avg
total 20920 writes, 25.975 sec, 997.1 kb/call avg, 1.2 msec/call avg
實測查詢效能
-
開啟searchd服務
/home/coreseek/bin/searchd -c /home/coreseek/etc/csft.conf
-
伺服器配置:CentOS7.6 16核4G記憶體
-
實測億級資料下搜尋晴空萬里只花費0.011秒,上文提到MySQL則需要242秒,效能差了22000倍。或許是受或分詞器影響,Sphinx查詢出來1898條,MySQL查詢資料為1931條
-
多次測試:在109450000條資料中,從不同角度測試Sphinx SPH_MATCH_PHRASE匹配模式,相當於mysql where field like '%關鍵字%':
型別 | 搜尋關鍵字 | Sphinx搜尋耗時(秒) | MySQL搜尋耗時(秒) | Sphinx搜尋數量 | MySQL搜尋數量 |
---|---|---|---|---|---|
數字 | 123 | 0.005 | 305.142 | 3121 | 8143 |
中文單字 | 虹 | 0.013 | 223.184 | 67802 | 103272 |
英文單字母 | A | 0.031 | 339.576 | 136428 | 1017983 |
單中文標點 | 。 | 4.471 | 125.106 | 67088012 | 67096182 |
單英文標點 | . | 0 | 251.171 | 0 | 6697242 |
可列印特殊字元 | ☺ | 0 | 355.469 | 0 | 0 |
中文詞語(易分詞) | 黑色衣服 | 0.066 | 346.442 | 1039 | 1062 |
中文詞語(不易分詞) | 夏威夷 | 0.011 | 127.054 | 3636 | 3664 |
中文詞語(熱門) | 你好 | 0.022 | 126.979 | 102826 | 137717 |
中文詞語(冷門) | 旖旎 | 0.010 | 345.493 | 4452 | 4528 |
英文單詞 | good | 0.010 | 137.562 | 553 | 1036 |
中文短語 | 他不禁一臉茫然 | 1.742 | 218.272 | 0 | 0 |
英文短語 | I am very happy | 0.015 | 355.235 | 1 | 0 |
長文字 | 陳大人不急著回答,他先從櫃檯下面又抽出了一份文案,翻了好一陣之後才回答道:“瞧,果然如此,如今廣州這邊官職該放得都放出去了,只剩下消防營山字營的一個哨官之職。不出所料的話,督撫大人準會委你這個職務。 | 0.131 | 129.204 | 1 | 1 |
實測Sphinx併發效能
壓測方式 :ab -c 1 -n 10~1000 192.168.3.180/test_coreseek.php
中文定值關鍵字為華盛頓,英文定值關鍵字為XYZ,30位隨機中文或英文字元,由程式碼生成。
生成任意正整數箇中文字元
function generateRandomChinese($length) {
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= mb_convert_encoding('&#' . mt_rand(0x3e00, 0x9fa5) . ';', 'UTF-8', 'HTML-ENTITIES');
}
return $result;
}
生成任意正整數個英文字元
function generateRandomEnglish($length) {
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= chr(mt_rand(97, 122)); // 小寫字母ASCII碼範圍: 97~122;大寫字母:65~90
}
return $result;
}
型別 | 請求量 (搜尋次數) | 耗時(秒) |
---|---|---|
固定中文多次搜尋 | 10 | 0.256 |
固定中文多次搜尋 | 100 | 1.435 |
固定中文多次搜尋 | 1000 | 11.604 |
隨機30位中文字元多次搜尋 | 10 | 0.517 |
隨機30位中文字元多次搜尋 | 100 | 2.305 |
隨機30位中文字元多次搜尋 | 1000 | 17.197 |
固定英文多次搜尋 | 10 | 0.327 |
固定英文多次搜尋 | 100 | 0.747 |
固定英文多次搜尋 | 1000 | 8.510 |
隨機30位英文字元多次搜尋 | 10 | 0.077 |
隨機30位英文字元多次搜尋 | 100 | 0.766 |
隨機30位英文字元多次搜尋 | 1000 | 9.428 |
建立增量索引前的資料查詢問題
對於update很多資料,sphinx不會自動更新索引,所以可以選擇在公司業務空閒時間重建索引。
對於insert,可以使用增量索引,建立一個表用於儲存已經新增sphinx索引記錄的最大值。
CREATE TABLE `sphinx_index_record` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Sphinx索引建立進度表id',
`table_name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表名',
`max_id` int unsigned NOT NULL COMMENT '最大id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
並insert一條資料:
INSERT INTO `test`.`sphinx_index_record` (`id`, `table_name`, `max_id`) VALUES (1, 'articles', 109450000);
- 對於Sphinx:當需要新增增量索引時,讀取這個表中的資料,獲取到這個值,使其建立索引的起始點,為max_id欄位的值。
- 對於max_id欄位的業務作用:可以封裝一個方法,可以讓這個值載入Redis,redis有值就讀取,無值就查詢然後載入Redis。
- 對於業務程式碼:例如100萬行資料建立了Sphinx索引,然後又新增了1000條,這1000條資料沒有sphinx索引,可以在業務程式碼中使用mysql union或者其它方式,讓這1000條資料,做查詢。
虛擬碼如下:
$max_id = 從快取中獲取獲取的索引位置,假設是100萬;
$kw = 搜尋關鍵字;
$id_s = sphinx($kw);
sql1是根據sphinx的
$sql1 = select * from table where id in $id_s;
sql2是對未新增sphinx索引的剩餘表資料的操作
$sql2 = select * from table where id > $max_id like "%$kw%";
使用PHP的方式,或者mysql union的方式都行,讓兩個資料集合並,查詢出的結果,透過介面返回。
這樣兼顧新增的1000條資料也能被查詢的到。
建立增量索引
這塊需要承接上文。
第一步:自動維護索引最大值,這一步可以在首次建立索引時,就可以完成。
vim /home/coreseek/etc/csft.conf
在source段最後,新增一行程式碼,這是讓sphinx建立增量索引後,自動維護sphinx_index_record表資料。
source articles {
...
...
sql_query_post = update sphinx_index_record set max_id = (select max(id) from articles) where table_name = 'articles';
}
第二步:新增增量索引配置
把source段複製出來,然後貼上到下方,注意括號範圍,不要巢狀,例如:
source articles_add
{
type = mysql
sql_host = 資料庫IP
sql_user = 資料庫使用者名稱
sql_pass = 資料庫密碼
sql_db = 資料庫
sql_port = 3306 埠
sql_query_pre = select names utf8mb4 加上這行
-------------------------------修改這裡start-------------------------------------------
sql_query = select id,content from articles where id > (select max_id from sphinx_index_record where table_name = 'articles') Sphinx建立增量索引的資料來源
-------------------------------修改這裡end-------------------------------------------
sql_attr_uint = group_id 這行用不上可以去掉
sql_attr_timestamp = date_added 這行用不上可以去掉
sql_query_info_pre = select names utf8mb4 加上這行
sql_query_info = select id,content from articles where id=$id 用Sphinx做什麼SQL的查詢邏輯
}
這裡記得index段也新增一個配置。永遠記住,source段與index段一對一的。
index articles_add 這裡需要改
{
source = articles_add 這裡需要改
path = /home/coreseek/var/data/articles_add 這裡需要改
#docinfo = extern
charset_dictpath = /home/mmseg/etc
charset_type = zh_cn.utf-8
}
執行建立索引功能。
/home/coreseek/bin/indexer -c /home/coreseek/etc/csft.conf articles_add
合併索引:語法indexer --merge 主索引名 增量索引名
/home/coreseek/bin/indexer --merge articles articles_add
如果不關閉searchd,可以新增 --rotate引數強制合併索引。
需要留意一下:如果主索引10個G,增量索引0.1G,則需要20.2G的臨時空間去進行和合並。
多配置
這個也好辦,直接在csft.conf配置檔案內source段和index段複製貼上,根據上文的兩段文章,該建立索引的建立索引,該重啟的重啟。
不需要引入多個檔案,就和MySQL一樣,只需要一個/etc/my.cnf就行了,相加配置,接著往下續就行了。
新建立索引後不會生效,需要關閉searchd程序後重新啟動。
整合到框架思路
方案1:
使用composer安裝新的包,PHP8.0及以上不會報錯。
記得要搜尋sphinx client或sphinxapi,不要搜素sphinx,這會把SphinxQL的解決方案也給搜出來。
用這個包就行,composer require nilportugues/sphinx-search
用法與自帶的完全一致,而且遇到PHP8不報錯。
$sphinx = new \NilPortugues\Sphinx\SphinxClient();
$sphinx->setServer('192.168.3.180',9312);
$sphinx->SetConnectTimeout (3);
$sphinx->SetArrayResult (true);
$sphinx->SetMatchMode (SPH_MATCH_PHRASE);
$sphinx->SetLimits(0, 200);
$res = $sphinx->query ("黑色衣服", "articles");
print_r($res);
方案2:
使用原生自帶的包,PHP8.0及以上會報錯。
sphinxapi.php放置到app/Libs/Others目錄下,並新增自己的名稱空間App\Libs\Others\SphinxApi。
app/Libs/helper.php存放了自定義封裝的方法,並使用composer dump-autoload配置,跟隨框架自動載入。
封裝成一個方法,方便呼叫,並放入helper.php下
function sphinx() {
$sphinx = new App\Libs\Others\SphinxApi();
$sphinx->SetServer (config('services.sphinx.ip'), config('services.sphinx.port'));
$sphinx->SetConnectTimeout (config('services.sphinx.timeout');
$sphinx->SetArrayResult (true);
return $sphinx;
}
//控制器隨處呼叫
$sphinx = sphinx();
$sphinx->SetMatchMode (SPH_MATCH_PHRASE);
$sphinx->SetLimits(0, 200);
$res = $sphinx->Query ("黑色衣服", "索引名稱");
...
Sphinx的不足之處
- 查詢結果遺漏:受分詞器影響,實測查詢結果比實際的儲存要少一些,這會造成資訊的損失。
- 客戶端程式碼陳舊:自帶的的PHP Sphinx Api的程式碼,使用PHP8.0及以上會報錯。
- 不會自動新增增量索引:MySQL新增的資料,Sphinx並不會自動建立索引。
- 不會自動改變索引:MySQL update的資料,Sphinx不會自動改變索引。
- 不支援Canal監聽bin log實時同步Sphinx索引。
鳴謝
感謝3位博主在C++編譯安裝報錯時提供的解決方案:
夜裡小郎君的博文:https://blog.csdn.net/b876143268/article/details/53771310
mingaixin的博文:https://www.cnblogs.com/mingaixin/p/5013356.html
晚晚的博文:https://www.cnblogs.com/caochengli/articles/3028630.html