這是半年前沒有對外寫的文章,現在拿出來分享下。可能會有一些不正確或不嚴謹的地方,某些語言可能比較輕浮,請見諒。
以上一篇的email資料表為例:
資料結構:
CREATE TABLE email (emailid mediumint(8) unsigned NOT NULL auto_increment COMMENT '郵件id',fromid int(10) unsigned NOT NULL default '0' COMMENT '發送人ID',toid int(10) unsigned NOT NULL default '0' COMMENT '收件者ID',content text unsigned NOT NULL COMMENT '郵件內容',subject varchar(100) unsigned NOT NULL COMMENT '郵件標題',sendtime int(10) NOT NULL COMMENT '發送時間',attachment varchar(100) NOT NULL COMMENT '附件ID,以逗號分割', PRIMARY KEY (emailid),) ENGINE=MyISAM';
使用開啟控制台,必需開啟控制台PHP才能串連到sphinx(確保你已經建立好索引源):
d:\coreseek\bin\searchd -c d:\coreseek\bin\sphinx.conf
coreseek/api目錄下提供了PHP的介面檔案 sphinxapi.php,這個檔案包含一個SphinxClient的類
在PHP引入這個檔案,new一下
$sphinx = new SphinxClient();//sphinx的主機名稱和連接埠$sphinx->SetServer ( 'loclahost', 9312 );//設定返回結果集為php數組格式$sphinx->SetArrayResult ( true );//匹配結果的位移量,參數的意義依次為:起始位置,返回結果條數,最大匹配條數$sphinx->SetLimits(0, 20, 1000);//最大搜尋時間$sphinx->SetMaxQueryTime(10); //執行簡單的搜尋,這個搜尋將會查詢所有欄位的資訊,要查詢指定的欄位請繼續看下文$index = 'email' //索引源是設定檔中的 index 類,如果有多個索引源可使用,號隔開:'email,diary' 或者使用'*'號代表全部索引源$result = $sphinx->query ('搜尋索引鍵', $index); echo '
';print_r($result);echo '
';
$result是一個數組,其中
total是匹配到的資料總數量
matches是匹配的資料,包含id,attrs這些資訊
words是搜尋索引鍵的分詞
你可能奇怪為什麼沒有郵件的內容這些資訊,其實sphinx並不會返回像mysql那樣的資料數組,因為sphinx本來就沒有記錄完整的資料,只記錄被分詞後的資料。
具體還要看matches數組,matches中的ID就是指設定檔中sql_query SELECT語句中的第一個欄位,我們設定檔中是這樣的
sql_query = SELECT emailid,fromid,toid,subject,content,sendtime,attachement FROM email
所以matches中的ID是指emailid
至於weight是指匹配的權重,一般權重越高被返回的優先度也最高,匹配權重相關內容請參考官方文檔
attrs是設定檔中sql_attr_ 中的資訊,稍後會提到這些屬性的用法
說了這麼多,即使搜尋到結果也不是我們想要的email資料,但事實sphinx是不記錄真實資料的,所以要擷取到真實email資料還要根據matches中的ID去搜尋mysql的email表,但總體來說這樣一來一回的速度還是遠遠比mysql的LIKE快得多,前提是幾十萬資料量以上,否則用sphinx只會更慢。
接下來介紹sphinx一些類似mysql條件的用法
//emailid的範圍$sphinx->SetIdRange($min, $max); //屬性過濾,可過濾的屬性必需在設定檔中設定sql_attr_ ,之前我們定義了這些 sql_attr_uint = fromid sql_attr_uint = toid sql_attr_timestamp = sendtime//如果你想再次修改這些屬性,配置完成後記得重建立立索引才會生效 //指定一些值$sphinx->SetFilter('fromid', array(1,2)); //fromid的值只能是1或者2//和以上條件相反,可增加第三個參數$sphinx->SetFilter('fromid', array(1,2), false); //fromid的值不能是1或者2//指定一個值的範圍$sphinx->SetFilterRange('toid', 5, 200); //toid的值在5-200之間//和以上條件相反,可增加第三個參數$sphinx->SetFilterRange('toid', 5, 200, false); //toid的值在5-200以外 //執行搜尋$result = $sphinx->query('關鍵字', '*');
排序模式
可使用如下模式對搜尋結果排序:
SPH_SORT_RELEVANCE 模式, 按相關度降序排列(最好的匹配排在最前面)
SPH_SORT_ATTR_DESC 模式, 按屬性降序排列 (屬性值越大的越是排在前面)
SPH_SORT_ATTR_ASC 模式, 按屬性升序排列(屬性值越小的越是排在前面)
SPH_SORT_TIME_SEGMENTS 模式, 先按時間段(最近一小時/天/周/月)降序,再按相關度降序
SPH_SORT_EXTENDED 模式, 按一種類似SQL的方式將列組合起來,升序或降序排列。
SPH_SORT_EXPR 模式,按某個算術運算式排序
//使用屬性排序//以fromid倒序排序,注意當再次使用SetSortMode會覆蓋上一個排序$sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid');//如果要使用多個欄位排序可使用SPH_SORT_EXTENDED模式//@id是sphinx內建關鍵字,這裡指emailid,至於為什麼是emailid,自己思考一下$sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid ASC, toid DESC, @id DESC');//執行搜尋$result = $sphinx->query('關鍵字', '*');
//更多請查看官方文檔排序模式的說明
匹配模式
有如下可選的匹配模式:
SPH_MATCH_ALL, 匹配所有查詢詞(預設模式);
SPH_MATCH_ANY, 匹配查詢詞中的任意一個;
SPH_MATCH_PHRASE, 將整個查詢看作一個片語,要求按順序完整匹配;
SPH_MATCH_BOOLEAN, 將查詢看作一個布林運算式
SPH_MATCH_EXTENDED, 將查詢看作一個CoreSeek/Sphinx內部查詢語言的運算式 . 從版本Coreseek 3/Sphinx 0.9.9開始, 這個選項被選項SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的效能。保留這個選項是為了與遺留的舊代碼相容——這樣即使Sphinx及其組件包括API升級的時候,舊的應用程式代碼還能夠繼續工作。
SPH_MATCH_EXTENDED2, 使用第二版的“擴充匹配模式”對查詢進行匹配.
SPH_MATCH_FULLSCAN, 強制使用下文所述的“完整掃描”模式來對查詢進行匹配。注意,在此模式下,所有的查詢詞都被忽略,儘管過濾器、過濾器範圍以及分組仍然起作用,但任何文本匹配都不會發生.
我們要關注的主要是SPH_MATCH_EXTENDED2擴充匹配模式,擴充匹配模式允許使用一些像mysql的條件陳述式
//設定擴充匹配模式$sphinx->SetMatchMode ( "SPH_MATCH_EXTENDED2" );//查詢中使用條件陳述式,欄位用@開頭,搜尋內容包含測試,toid等於1的郵件:$result = $sphinx->query('@content (測試) & @toid =1', '*');//用括弧和&(與)、|、(或者)、-(非,即!=)設定更複雜的條件$result = $sphinx->query('(@content (測試) & @subject =呃) | (@fromid -(100))', '*');//更多文法請查看官方文檔匹配模式的說明
擴充匹配模式中值得一提的是搜尋的欄位,如果該欄位被設定屬性,那麼擴充匹配搜尋的欄位預設是不包含這些屬性的,只能用SetFilter()或者SetFilterRange()之類
之前我們設定了fromid、toid、sendtime為屬性,但又想在擴充匹配模式中又想用作條件該怎麼辦?
只要在sql_query語句中再選擇多一次該欄位就可以了
sql_query = SELECT emailid,fromid,fromid,toid,toid,subject,content,sendtime,sendtime,attachement FROM email
//設定完成記得重建立立索引
更多條件技巧
只是一些技巧,但不建議使用的部署環境中,至於為什麼,請看文章結尾
<、<=、>、>=
預設sphinx沒有這些比較符。
假如我想郵件的發送時間大於某一日期怎麼辦?用SetFilterRange()方法類比一下
//大於等於某一時間截$time$sphinx->SetFilterRange('sendtime', $time, 10000000000) //時間截最大是10個9,再加1是不可超越了。。 //大於某一時間截$time$sphinx->SetFilterRange('sendtime', $time+1, 10000000000)//小於等於某一時間截$time$sphinx->SetFilterRange('sendtime', -1, $time) //時間截最小是0,所以應該減1//大於某一時間截$time$sphinx->SetFilterRange('sendtime', -1, $time - 1)
IS NOT NULL
怎樣搜尋為空白的欄位,比如我要搜尋附件為空白的郵件,有人可能會想 @attachment ('')不就可以了嗎?其實這是搜尋兩個單引號。。。sphinx搜尋的字串不用加引號的
目前sphinx是沒有提供這樣的功能,其實可以在mysql語句上作手腳:
sql_query = SELECT emailid,fromid,toidsubject,content,sendtime,attachement != '' as attach is not null FROM email //這裡返回了一個新欄位attachisnotnull,當attachisnotnull為1的時候附件就不為空白了
//設定完成記得重建立立索引
FIND_IN_SET()
搜尋包含某一附件的郵件,mysql習慣用FIND_IN_SET這麼簡單一句就搞定了,在sphinx中必需在配置裡設定屬性sql_attr_multi 多值屬性(MVA):
sql_attr_multi = attachment #attachment可以是逗號分隔的附件ID,或者是空格、分號等sphinx都能識別
//設定完成記得重建立立索引 然後PHP中可以使用SetFilter()//搜尋包含附件ID為1或2郵件,mysql文法是這樣FIND_IN_SET(`attachment`, '1,2')$sphinx->SetFilter('attachment', array(1,2))//可以使用SetFilterRange,搜尋包含附件ID在50-100範圍的郵件$sphinx->SetFilterRange('attachment', 50, 100)
總結
如果你想一個免費、好用、極速的全文檢索搜尋引擎,sphinx無疑是最好的選擇,但是不要忘記sphinx的目的:全文檢索索引。不要去想那些亂七八糟條件。你想要把sphinx搜尋變得像mysql那樣靈活,可完全單獨用在一些複雜的多條件搜尋,像某些郵件的進階搜尋,那麼我建議你還是多花點時間在PHP或者mysql代碼的最佳化上,因為那樣可能會讓你的搜尋變得更慢。
最好的方法是以最簡單的方法搜尋到內容,將ID交還mysql資料庫搜尋。
http://www.bkjia.com/PHPjc/444552.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/444552.htmlTechArticle這是半年前沒有對外寫的文章,現在拿出來分享下。可能會有一些不正確或不嚴謹的地方,某些語言可能比較輕浮,請見諒。 以上一篇的...