DLc @sddkZddkZddkZddkZddkTdZdZdZdZdZ dZ d Z d Z d Z dZdZdZdZdZdZdZdZdZd Zd ZdZdZdZdZdZdZdZdZ dZ!d Z"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*d Z+d Z,d Z-e&e'e(e)e*e+e,e-fZ.dZ/dZ0dZ1dZ2dZ3d Z4dddYZ5dS(iN(t*iiiiiiiiiilt SphinxClientcBseZdZdZdZdZd)dZdZdZ dddZ d Z d Z d Z d d ZdZdZdZdZddZddZddZdZddZdZddZdZdZdZdZdZdd d Zdd d!Z d"Z!d)d#Z"d$Z#d%Z$d&Z%d'Z&d(Z'RS(*cCsd|_d|_d |_d |_d|_d|_t|_g|_ t |_ d|_ d|_ d|_g|_d|_t|_d|_d|_d|_d|_d|_d|_h|_h|_t|_d|_h|_h|_d|_ d|_!d|_"g|_#d S( s4 Create a new client object, and fill defaults. t localhosti`$iits @group desciRN($t_hostt_porttNonet_patht_sockett_offsett_limitt SPH_MATCH_ALLt_modet_weightstSPH_SORT_RELEVANCEt_sortt_sortbyt_min_idt_max_idt_filterst_groupbytSPH_GROUPBY_DAYt _groupfunct _groupsortt_groupdistinctt _maxmatchest_cutofft _retrycountt _retrydelayt_anchort _indexweightstSPH_RANK_PROXIMITY_BM25t_rankert _maxquerytimet _fieldweightst _overridest_selectt_errort_warningt_reqs(tself((s./sphinxapi.pyt__init__cs>                              cCs|io|iindS(N(Rtclose(R(((s./sphinxapi.pyt__del__s cCs|iS(s& Get last error message (string). (R%(R(((s./sphinxapi.pyt GetLastErrorscCs|iS(s( Get last warning message (string). (R&(R(((s./sphinxapi.pytGetLastWarningscCst|tpt|ido||_dS|ido|d|_dSt|tpt||_||_d|_dS(s' Set searchd server host and port. t/Nsunix://i( t isinstancetstrtAssertionErrort startswithRtintRRR(R(thosttport((s./sphinxapi.pyt SetServers    c Cs|iouti|ig|iggd\}}}t|djot|djo|iS|iid|_nyt|ioti}|i}|i}n&ti}|i |i f}d|}ti|ti }|i |WnAti j o2}|o|ind||f|_dSXtd|id} | djo|id| |_dS|itdd|S( s? INTERNAL METHOD, DO NOT CALL. Connects to searchd server. iis%s;%ssconnection to %s failed (%s)Ns>Lis)expected searchd protocol version, got %s(RtselecttlenR*RRtsockettAF_UNIXtAF_INETRRt SOCK_STREAMtconnectterrorR%tunpacktrecvtsendtpack( R(tsrtswt_taftaddrtdesctsocktmsgtv((s./sphinxapi.pyt_Connects8 -&           c Cstd|id\}}}d}|}xG|djo9|i|}|o||7}|t|8}q0Pq0W|ip|int|} | p | |jo2|od|||| f|_n d|_dS|tjo7dtd|dd!d} |d| !|_|| S|t jod |d|_dS|t jod |d|_dS|t jod ||_dS||jo-d |d?|d @|d?|d @f|_n|S(sX INTERNAL METHOD, DO NOT CALL. Gets and checks response packet from searchd server. s>2HLiRisDfailed to read searchd response (status=%s, ver=%s, len=%s, read=%s)s$received zero-sized searchd responseis>Lssearchd error: stemporary searchd error: sunknown status code %dsPsearchd command v.%d.%d older than client's v.%d.%d, some options might not workiN( R?R@R8RR*R%RtSEARCHD_WARNINGR&t SEARCHD_ERRORt SEARCHD_RETRYt SEARCHD_OK( R(RIt client_vertstatustvertlengthtresponsetlefttchunktreadtwend((s./sphinxapi.pyt _GetResponsesH!            *icCst|ttgjod|jo djnptt|ttgjod|jo djnpt|djpt||_||_|djo ||_n|djo ||_ndS(s] Set offset and count into result set, and optionally set max-matches and cutoff limits. iiN(ttypeR3tlongR1R R RR(R(toffsettlimitt maxmatchestcutoff((s./sphinxapi.pyt SetLimitss>>     cCs1t|to |djpt||_dS(sQ Set maximum query time, in milliseconds, per-index. 0 means 'do not limit'. iN(R/R3R1R!(R(t maxquerytime((s./sphinxapi.pytSetMaxQueryTimes$cCs6|tttttttgjpt||_dS(s Set matching mode. N( R t SPH_MATCH_ANYtSPH_MATCH_PHRASEtSPH_MATCH_BOOLEANtSPH_MATCH_EXTENDEDtSPH_MATCH_FULLSCANtSPH_MATCH_EXTENDED2R1R (R(tmode((s./sphinxapi.pyt SetMatchMode%s)cCs-|ttttgjpt||_dS(s Set ranking mode. N(Rt SPH_RANK_BM25t SPH_RANK_NONEtSPH_RANK_WORDCOUNTR1R (R(tranker((s./sphinxapi.pytSetRankingMode-s RcCsS|ttttttgjptt|tpt||_ ||_ dS(s Set sorting mode. N( RtSPH_SORT_ATTR_DESCtSPH_SORT_ATTR_ASCtSPH_SORT_TIME_SEGMENTStSPH_SORT_EXTENDEDt SPH_SORT_EXPRR1R/R0RR(R(Rjtclause((s./sphinxapi.pyt SetSortMode5s& cCsLt|tptx%|D]}t|tptqW||_dS(s` Set per-field weights. WARNING, DEPRECATED; do not use it! use SetFieldWeights() instead N(R/tlistR1R3R (R(tweightstw((s./sphinxapi.pyt SetWeights?s cCsot|tptxH|iD]:\}}t|tptt|tptq$W||_dS(sY Bind per-field weights by name; expects (name,field_weight) dictionary as argument. N(R/tdictR1titemsR0R3R"(R(Rytkeytval((s./sphinxapi.pytSetFieldWeightsJs  cCsot|tptxH|iD]:\}}t|tptt|tptq$W||_dS(sY Bind per-index weights by name; expects (name,index_weight) dictionary as argument. N(R/R|R1R}R0R3R(R(RyR~R((s./sphinxapi.pytSetIndexWeightsUs  cCsdt|ttfptt|ttfpt||jpt||_||_dS(sg Set IDs range to match. Only match records if document ID is beetwen $min and $max (inclusive). N(R/R3R\R1RR(R(tminidtmaxid((s./sphinxapi.pyt SetIDRange`s  cCst|tptt|ptx5|D]-}t|tpt|tptq2W|iihtd6|d6|d6|d6dS(sc Set values set filter. Only match records where 'attribute' value is in given 'values' set. R[tattrtexcludetvaluesN( R/R0R1titerR\R3RtappendtSPH_FILTER_VALUES(R(t attributeRRtvalue((s./sphinxapi.pyt SetFilterls +cCst|tptt|tptt|tpt||jpt|iihtd6|d6|d6|d6|d6dS(sk Set range filter. Only match records if 'attribute' value is beetwen 'min_' and 'max_' (inclusive). R[RRtmintmaxN(R/R0R1R3RRtSPH_FILTER_RANGE(R(Rtmin_tmax_R((s./sphinxapi.pytSetFilterRangezs cCst|tptt|tptt|tpt||jpt|iihtd6|d6|d6|d6|d6dS(NR[RRRR(R/R0R1tfloatRRtSPH_FILTER_FLOATRANGE(R(RRRR((s./sphinxapi.pytSetFilterFloatRanges cCst|tptt|tptt|tptt|tpt||id<||id<||id<||idtwarningRRN( R8R'R1tAddQueryt RunQueriesRR%R&RN(R(tquerytindextcommenttresults((s./sphinxapi.pytQuerys cCstd|i|i|i|i|ig}|itdt|i|i|it |t o|i d}nt |t pt |itdt||i||itdt|ix'|iD]}|itd|qW|itdt||i||itdd|itd|i|itd|i|itdt|ix3|iD](}|itdt|d|d|d}|itd||tjoO|itdt|dx|dD]}|itd |q(Wne|tjo%|itd |d |d n3|tjo%|itd |d |d n|itd|dqW|itd|it|i|i|i|itd|it|i|i|i|itd|i|i|i|itdt|i|i|it|idjo|itddn|id|id} } |id|id} } |itdd|itdt| | |itdt| | |itd| td| |itdt|ixJ|iiD]9\} }|itdt| | td|qW|itd|i |itdt|i!xJ|i!iD]9\}}|itdt||td|qW|itdt|||itdt|i"x |i"i#D]}|i$tdt|d|df|itd|dt|dx|di%D]\}}|itd||dt&jo|itd|q|dt'jo|itd |q|itd|qWqW|itdt|i(|i|i(di)|}|i*i|dS(s Add query to batch. s>5Ls>Lsutf-8is>QRR[Rs>qs>2qRRs>2fRs>2Ls>LLLiRRRR\s>fRs>LLs>lRN(+RBR R R R RRR8RR/tunicodetencodeR0R1R RRRRRRRRRRRRRRRRR}R!R"R#Rtextendt iteritemstSPH_ATTR_FLOATtSPH_ATTR_BIGINTR$tjoinR'(R(RRRtreqRztft filtertypeRRRRRtindxtweighttfieldRKtidR((s./sphinxapi.pyRs-    (     % %%%%  # 1 1 *' cCs1t|idjod|_d!S|i}|pd!Sdi|i}t|d}tdtt|t|i|}|i ||i |t}|pd!St|i}t|}d}g}xLt d|dD]8} h} |i | d| dHHLLiR>Rs>LRRtfieldstattrstmatchess>QLi s>2LiRRs>fs>qs>4Littotalt total_foundttimes%.3fg@@twordstwordtdocsthitsN(R8R'R%RRLRRBtSEARCHD_COMMAND_SEARCHtVER_COMMAND_SEARCHRARZtrangeRR?RPRMRRtSPH_ATTR_MULTItSPH_ATTR_INTEGER(R(RIRRTRUtnreqsRtpRtitresultRRtmessageRRtnfieldstnattrsRttype_Rtid64tdocRtmatchtnvalstnRRRR((s./sphinxapi.pyRMs  %                             2. 5.2        / c CsC|p h}nt|to|id}nt|tptt|tptt|tptt|tpt|i}|pdS|i dd|i dd|i dd|i dd |i d d d }|i d o|dO}n|i do|dO}n|i do|dO}n|i do|dO}nt dd|g}|i t dt ||i ||i t dt ||i ||i t dt |d|i |d|i t dt |d|i |d|i t dt |d|i |d|i t dt|d|i t dt|d |i t dt |xq|D]i}t|to|id}nt|tpt|i t dt ||i |qWdi|}t |} t dtt| |}|i|} |i|t} | pgSd} g} t | }xtt |D]o}td| | | d!d} | d7} | | |jod|_gS| i | | | | !| | 7} qW| S(sK Connect to searchd server and generate exceprts from given documents. sutf-8t before_matchst after_matchstchunk_separators ... R^itaroundiit exact_phraseitsingle_passageituse_boundariesit weight_orderis>2Lis>LRs>2HLsincomplete replyN(R/RRRxR1R0R|RLRt setdefaulttgetRBRR8R3RtSEARCHD_COMMAND_EXCERPTtVER_COMMAND_EXCERPTRARZRR?R%(R(RRRtoptsRItflagsRRRTtwroteRUtpostrestrlenR((s./sphinxapi.pyt BuildExcerptss             c Csut|tptt|tptt|tptx%|D]}t|tptqLWx|iD]\}}t|tptt|tptt|t|jptx%|D]}t|tptqWqzWtdt||g}|i tdt|x.|D]&}|i tdt||q>W|i tdt|xW|iD]I\}}|i td|x$|D]}|i td|qWqW|i } | pdSdi |}t|} tdt t| |}| i|} |i| t} | pdStd| dd!d} | S( s Update given attribute values on given documents in given indexes. Returns amount of updated documents (0 or more) on success, or -1 on failure. 'attrs' must be a list of strings. 'values' must be a dict with int key (document ID) and list of int values (new attribute values). Example: res = cl.UpdateAttributes ( 'test1', [ 'group_id', 'date_added' ], { 2:[123,1000000000], 4:[456,1234567890] } ) s>Ls>QRs>2HLiiiN(R/R0R1RxR|R}R3R8RBRRLRRtSEARCHD_COMMAND_UPDATEtVER_COMMAND_UPDATERARZR?(R(RRRRtdocidtentryRRRIRTRRUtupdated((s./sphinxapi.pytUpdateAttributes;sL   $   c Cs~t|tptt|tptt|tpttdt||g}|itdt|||itd||i}|pdSdi |}t|}tdt t ||}|i |}|i |t }|pdSg} td|dd!d} d} t|} x | djo| | jo| d8} td|| | d!d}| d7} || | |!} | |7} td|| | d!d}| d7} || | |!}| |7} h| d6|d6}|o6td || | d !\|d <|d <| d 7} n| i|qEW| djp | | jod |_dS| S(s Connect to searchd server, and generate keywords list for a given query. Returns None on failure, or a list of keywords on success. s>LRs>2HLiiit tokenizedt normalizeds>2LiRRsincomplete replyN(R/R0R1R3RBR8RRLRRtSEARCHD_COMMAND_KEYWORDStVER_COMMAND_KEYWORDSRARZR?R%(R(RRRRRIRTRRURtnwordsRRRRR((s./sphinxapi.pyt BuildKeywordsrsP         ( cCsb|iod|_dS|i}|pdStdtddd}|i|||_dS(Nsalready connecteds>hhIIiii(RR%RLRBtSEARCHD_COMMAND_PERSISTRA(R(tservertrequest((s./sphinxapi.pytOpens    cCs2|ipd|_dS|iid|_dS(Ns not connected(RR%R*R(R(((s./sphinxapi.pytCloses    cCstidd|S(Ns([=\(\)|\-!@~\"&/\\\^\$\=])s\\\1(tretsub(R(tstring((s./sphinxapi.pyt EscapeStringsN((t__name__t __module__R)R+R,R-RR6RLRZRaRcRkRpRwR{RRRRRRRRRRRRRRRRRRRRRRRR (((s./sphinxapi.pyRbsJ %     , 6            f d 7 ?  ((6tsysR7R9RtstructRRRRRRRRRRPRNRORMR RdReRfRgRhRiRRlRmRnRRqRrRsRtRuRRRt SPH_ATTR_NONERtSPH_ATTR_TIMESTAMPtSPH_ATTR_ORDINALt SPH_ATTR_BOOLRRRRRRRRRRR(((s./sphinxapi.pytsx