蘇寧網(wǎng)站開發(fā)人員工資seo關(guān)鍵詞快速獲得排名
一、php連接sphinx的長連接事宜以及sphinx的排除查詢
????在使用php連接sphinx時(shí),默認(rèn)的sphinx連接非長連接,于是在想php連接sphinx能否進(jìn)行一些優(yōu)化 publish:January 9, 2018 -Tuesday:
????方法:public bool SphinxClient::open ( void ) — 建立到搜索服務(wù)端的持久連接。此函數(shù)沒有參數(shù)。成功時(shí)返回 TRUE,或者在失敗時(shí)返回FALSE。在網(wǎng)上了解到php調(diào)用sphinx api進(jìn)行長連接時(shí),并不是我們想象中的那樣會在php-fpm的fastcgi狀態(tài)下一直與sphinx的searchd進(jìn)程保持長連接,sphinx的api接口中open()方法僅僅提供了在一次會話請求中保證多個(gè)sphinx調(diào)用在單個(gè)php進(jìn)程中是共用一個(gè)sphinx tcp連接通道,當(dāng)php解釋運(yùn)行完,與sphinx的連接也會自動斷開,而不是保持連接狀態(tài)??吹竭@里我覺得我的業(yè)務(wù)中使用這項(xiàng)那就沒有什么意義了,因?yàn)槲业臉I(yè)務(wù)中基本都是連接sphinx執(zhí)行一次查詢?nèi)缓蠼Y(jié)束。不過我在線上業(yè)務(wù)時(shí)謹(jǐn)慎地在一臺服務(wù)器上嘗試查看這種情況.
????在一臺WEB上打開長連接,同時(shí)觀察著sphinx的連接數(shù)據(jù)(我這里中間有haproxy作為中轉(zhuǎn)),如果這個(gè)長連接能實(shí)現(xiàn)php與searchd的長連接,那么改了一臺服務(wù)器后,因?yàn)榫€上一直有請求,則我的WEB上所有的PHP-FPM進(jìn)程就應(yīng)該都能保持一個(gè)與sphinx的連接(單臺WEB上是60個(gè)php進(jìn)程,理論上應(yīng)該proxy上的sphinx請求能增加到60左右),而如果真是在php請求結(jié)束后就斷開sphinx,則不會對proxy上的數(shù)據(jù)有任何影響。使用之后發(fā)現(xiàn)這個(gè)數(shù)據(jù)確實(shí)沒有什么變化。如下圖即是我依據(jù)的數(shù)據(jù):
????而如果sphinx的長連接真的只有這個(gè)意義的話,那我感覺它沒有什么意義,因?yàn)樵谝粋€(gè)php請求中,除非我們自己去關(guān)閉,否則它不會關(guān)閉(當(dāng)然超時(shí)除外,但這種情況正常情況基本不會出現(xiàn))。查看spinx的api看的open方法,發(fā)現(xiàn)其就是判斷當(dāng)前是否connect,如果連接了就返回false,如果沒有就執(zhí)行一次連接。而實(shí)際在執(zhí)行query查詢的時(shí)候它本身也會去調(diào)用_Connect判斷并重新連接了sphinx,即表示即使在php進(jìn)程執(zhí)行中sphinx連接超時(shí)中斷,但隨后你再進(jìn)行query查詢,依然會自動連接sphinx.不需要保存這個(gè)長連接。sphinx的api里的open方法如下:
#sphinx的api中的open方法
function Open()
{if ( $this->_socket !== false ){$this->_error = 'already connected';return false;}if ( !$fp = $this->_Connect() )return false;// command, command version = 0, body length = 4, body = 1$req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 );if ( !$this->_Send ( $fp, $req, 12 ) )return false;$this->_socket = $fp;return true;
}#open方法里調(diào)用的_Send方法
function _Send ( $handle, $data, $length )
{if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ){$this->_error = 'connection unexpectedly closed (timed out?)';$this->_connerror = true;return false;}return true;
}
????如果不能保持php-fpm進(jìn)程與sphinx的長連接,依然是每次客戶端向php發(fā)送請求(即使是同一個(gè)php-fpm進(jìn)程處理),仍需要執(zhí)行sphinx連接的話,確實(shí)未發(fā)現(xiàn)這個(gè)open方法有什么意義。
????在使用sphinx時(shí),大多數(shù)情況下是進(jìn)行過濾,但有時(shí)有特殊需要進(jìn)行一些排它查詢,比如不需要某個(gè)ID的值出來。比如:在查詢某篇文章相關(guān)聯(lián)的文章時(shí),不要把這篇文章本身查詢出來。如果你的article_id字段在sphinx配置文件建的是字段xmlpipe_field_string,則可以使用:
$query.="!@article_id ".$id; #注意@號之前的感嘆號
$Sphinx->query($query)
?如果你的article_id字段在sphinx配置文件建的是屬性xmlpipe_attr_uint,則可以使用:
$Sphinx->SetFilter('article_id', array($id), true); #注意最后一個(gè)參數(shù),其就是排除的意義
?二、關(guān)于sphinx里使用SetSelect進(jìn)行復(fù)雜的條件過濾或復(fù)雜查詢
????sphinx提供了filter過濾以及通過關(guān)鍵詞進(jìn)行query查詢,但簡單的query一個(gè)關(guān)鍵詞并不能滿足我們的查詢要求,filter并不能支持復(fù)雜的邏輯組合運(yùn)算,過濾條件都只是多重的疊加,即AND操作,并不支持。比如我們有很多文章內(nèi)容及其它屬性已經(jīng)建好索引,如果要在一次查詢中實(shí)現(xiàn)查詢今天發(fā)表的新聞和昨天發(fā)表的非新聞文章中帶有關(guān)鍵詞新聞的內(nèi)容查詢出來。如果使用filter的話就沒法處理了,因?yàn)閒ilter即不能用于過濾文章類別,也不能用于過濾發(fā)表時(shí)間。
????可見sphinx的filter不能用于單條件多重過濾,如上即時(shí)間不能過濾今天同時(shí)又過濾昨天,類別不能用于過濾新聞又同時(shí)過濾非新聞。這個(gè)時(shí)間我們就要考慮使用sphinx的復(fù)雜查詢了。
????寫過SQL的話我們一定對復(fù)雜查詢不陌生,sphinx的復(fù)雜查詢的實(shí)現(xiàn)方式有點(diǎn)類似于自定義的SQL查詢。從而篩選出我們需要的數(shù)據(jù)。寫sphinx的復(fù)雜查詢就相當(dāng)于寫mysql的where條件。
????SetSelect這個(gè)api,可以實(shí)現(xiàn)sphinx進(jìn)行自定義復(fù)雜查詢條件 publish:January 12, 2018 -Friday。
#(PECL sphinx >= 1.0.1)
#SphinxClient::setSelect — Set select clause
public bool SphinxClient::setSelect ( string $clause )
#Sets the select clause, listing specific attributes to fetch, and expressions to compute and fetch.
?我目前使用過的sphinx里SetSelect的幾個(gè)復(fù)雜SQL寫法如下,當(dāng)然肯定不只這些。
1:計(jì)算數(shù)據(jù)值
????????有時(shí)內(nèi)容的權(quán)重并不是依靠某個(gè)字段,而是依靠一個(gè)計(jì)算值,比如把文章按總熱度排序,假設(shè)我們的條件是把文章的評論數(shù)以閱讀數(shù)的1%相加來得出,這時(shí)我們就可以使用下面的方法來計(jì)算:
#根據(jù)多個(gè)字段計(jì)算數(shù)值as成某個(gè)字段(像sql)一樣,然后在后面再利用這個(gè)字段,比如SetSortMode使用weighta排序
$cl->SetSelect ( "*, (views * 0.01 + comments) AS weighta" );
2:簡單if判斷
????????比如要查詢今天發(fā)表的新聞和昨天之后發(fā)表的非新聞文章。
#先設(shè)置生成myfilter字段,再用filter過濾這個(gè)字段為真即可
$cl->SetSelect ( "*, ( if( ((public_time>=16843434 , 1,0) AND type=1 ) AND ((public_time>=16813434 , 1,0) AND type>1 ) ) AS myfilter" );
3:IN查詢
????????比如要查詢PHP和sphinx以及l(fā)inux等類欄目中里今天發(fā)表的文章。
#如下1,2,3,4分別是各類的ID,使用逗號分開直接寫在過濾字段后面,
$cl->SetSelect ( "*, IF( IN(type, 1,2,3,4) AND public_time>=16843434, 1, 0) AS myfilter" );
?其它:
????????另外查詢中還可以使用@調(diào)用sphinx的數(shù)據(jù),比如 @weight可以調(diào)用sphinx系統(tǒng)中的權(quán)重值,可拿來進(jìn)行進(jìn)一步的計(jì)算。Starting with version 0.9.9-rc2, 復(fù)雜查詢中可以支持aggregate functions (AVG(), MIN(), MAX(), SUM()) are supported when using GROUP BY.