2010-06-25 08:54:04 +00:00
|
|
|
|
<?php
|
|
|
|
|
class Search
|
|
|
|
|
{
|
|
|
|
|
var $terms;
|
|
|
|
|
var $text;
|
2012-12-16 08:40:08 +00:00
|
|
|
|
var $xs;
|
|
|
|
|
var $search;
|
|
|
|
|
var $error;
|
|
|
|
|
var $pager;
|
|
|
|
|
var $count;
|
|
|
|
|
var $related;
|
|
|
|
|
var $corrected;
|
|
|
|
|
var $total;
|
|
|
|
|
var $search_cost;
|
|
|
|
|
var $docs;
|
|
|
|
|
var $hot;
|
|
|
|
|
var $base_url;
|
|
|
|
|
var $expanded;
|
|
|
|
|
|
|
|
|
|
//require_once '/home/wlx/xunsearch/sdk/php/lib/XS.php';
|
2010-06-25 08:54:04 +00:00
|
|
|
|
|
|
|
|
|
private function safe_query($search)
|
|
|
|
|
{
|
|
|
|
|
return preg_replace('/%|_|\'|\\\\/', '\\\\$0', stripslashes($search));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parse_search($search="", $safe = true)
|
|
|
|
|
{
|
|
|
|
|
if (empty($search)) $search=$this->text;
|
|
|
|
|
$temp = array();
|
|
|
|
|
preg_match_all('/"([^"]+)"|([^\\s]+)/', (( $safe ) ? $this->safe_query($search) : $search), $temp);
|
|
|
|
|
|
|
|
|
|
for ($i = 1; $i < count($temp); $i++)
|
|
|
|
|
{
|
|
|
|
|
foreach ( $temp[$i] as $value )
|
|
|
|
|
{
|
|
|
|
|
if ( strlen($value) >= 3 )
|
|
|
|
|
{
|
|
|
|
|
$this->terms[] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function sql_expr($field)
|
|
|
|
|
{
|
|
|
|
|
$sql=" 1=1 ";
|
|
|
|
|
if (!is_array($field))
|
|
|
|
|
{
|
|
|
|
|
$field=array($field);
|
|
|
|
|
}
|
|
|
|
|
if (!count($this->terms))
|
|
|
|
|
$this->parse_search();
|
|
|
|
|
foreach($this->terms as $t)
|
|
|
|
|
{
|
|
|
|
|
$sql.=" and (1<>1 ";
|
|
|
|
|
foreach($field as $f)
|
|
|
|
|
{
|
|
|
|
|
$sql.=" or ".$f." ilike '%".$t."%' ";
|
|
|
|
|
}
|
|
|
|
|
$sql.=") ";
|
|
|
|
|
}
|
|
|
|
|
return $sql;
|
|
|
|
|
}
|
2012-12-16 08:40:08 +00:00
|
|
|
|
function __construct($text='')
|
|
|
|
|
{
|
2014-06-11 01:27:50 +00:00
|
|
|
|
require_once '/home/wlx/xunsearch/sdk/php/lib/XS.php';
|
|
|
|
|
$config = Zend_Registry::get('config');
|
|
|
|
|
$this->xs=new XS($config->sub->search);
|
2012-12-16 08:40:08 +00:00
|
|
|
|
$this->search=$this->xs->search;
|
|
|
|
|
$this->terms = array();
|
|
|
|
|
$this->text=$text;
|
|
|
|
|
|
|
|
|
|
// other variable maybe used
|
|
|
|
|
$this->count = $this->total = $this->search_cost = 0;
|
|
|
|
|
$this->docs = $this->related = $this->corrected =$this->expanded = $this->hot = array();
|
|
|
|
|
$this->error = $this->pager = $this->base_url='';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function dosearch()
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// 支持的 GET 参数列表
|
|
|
|
|
// q: 查询语句
|
|
|
|
|
// m: 开启模糊搜索,其值为 yes/no
|
|
|
|
|
// f: 只搜索某个字段,其值为字段名称,要求该字段的索引方式为 self/both
|
|
|
|
|
// s: 排序字段名称及方式,其值形式为:xxx_ASC 或 xxx_DESC
|
|
|
|
|
// p: 显示第几页,每页数量为 XSSearch::PAGE_SIZE 即 10 条
|
|
|
|
|
// ie: 查询语句编码,默认为 UTF-8
|
|
|
|
|
// oe: 输出编码,默认为 UTF-8
|
|
|
|
|
// xml: 是否将搜索结果以 XML 格式输出,其值为 yes/no
|
|
|
|
|
//
|
|
|
|
|
// variables
|
|
|
|
|
$eu = '';
|
2013-06-02 03:50:09 +00:00
|
|
|
|
$__ = array('q', 'm', 'f', 's', 'p', 'ie', 'oe', 'syn', 'xml','east','west','south','north','begin','end');
|
2012-12-16 08:40:08 +00:00
|
|
|
|
foreach ($__ as $_)
|
|
|
|
|
$$_ = isset($_GET[$_]) ? $_GET[$_] : '';
|
|
|
|
|
|
|
|
|
|
// recheck request parameters
|
|
|
|
|
$q = get_magic_quotes_gpc() ? stripslashes($q) : $q;
|
|
|
|
|
$f = empty($f) ? '_all' : $f;
|
|
|
|
|
${'m_check'} = ($m == 'yes' ? ' checked' : '');
|
|
|
|
|
${'syn_check'} = ($syn == 'yes' ? ' checked' : '');
|
|
|
|
|
${'f_' . $f} = ' checked';
|
|
|
|
|
${'s_' . $s} = ' selected';
|
|
|
|
|
if (!isset($q)) $q='';
|
|
|
|
|
// base url
|
2013-06-02 03:50:09 +00:00
|
|
|
|
$this->base_url = '/search?q=' . urlencode($q) . '&m=' . $m . '&f=' . $f . '&s=' . $s .'&begin='.$begin.'&end='.$end.'&east='.$east.'&north='.$north.'&west='.$west.'&south='.$south. $eu;
|
2012-12-16 08:40:08 +00:00
|
|
|
|
|
|
|
|
|
$total_begin = microtime(true);
|
|
|
|
|
// perform the search
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
$this->search->setCharset('UTF-8');
|
|
|
|
|
|
|
|
|
|
if (empty($q))
|
|
|
|
|
{
|
|
|
|
|
// just show hot query
|
|
|
|
|
$this->hot = $this->search->getHotQuery();
|
|
|
|
|
}
|
2013-06-08 17:55:02 +00:00
|
|
|
|
|
2012-12-16 08:40:08 +00:00
|
|
|
|
{
|
|
|
|
|
// fuzzy search
|
|
|
|
|
$this->search->setFuzzy($m === 'yes');
|
|
|
|
|
|
|
|
|
|
// synonym search
|
|
|
|
|
$this->search->setAutoSynonyms($syn === 'yes');
|
|
|
|
|
|
|
|
|
|
// set query
|
|
|
|
|
if (!empty($f) && $f != '_all')
|
|
|
|
|
{
|
|
|
|
|
$this->search->setQuery($f . ':(' . $q . ')');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
$this->search->setQuery($q);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-02 03:50:09 +00:00
|
|
|
|
//spatial search
|
|
|
|
|
if (!empty($east) && !empty($west) && !empty($south) && !empty($north))
|
|
|
|
|
{
|
|
|
|
|
$this->search->addRange('east',null,$east);
|
|
|
|
|
$this->search->addRange('west',$west,null);
|
|
|
|
|
$this->search->addRange('south',$south,null);
|
|
|
|
|
$this->search->addRange('north',null,$north);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//date search
|
|
|
|
|
if (!empty($begin))
|
|
|
|
|
{
|
|
|
|
|
$from=strtotime($begin);
|
|
|
|
|
$this->search->addRange('timebegin',$from,null);
|
|
|
|
|
}
|
|
|
|
|
if (!empty($end))
|
|
|
|
|
{
|
|
|
|
|
$to=strtotime($end);
|
|
|
|
|
$this->search->addRange('timeend',null,$to);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-16 08:40:08 +00:00
|
|
|
|
// set sort
|
|
|
|
|
if (($pos = strrpos($s, '_')) !== false)
|
|
|
|
|
{
|
|
|
|
|
$sf = substr($s, 0, $pos);
|
|
|
|
|
$st = substr($s, $pos + 1);
|
|
|
|
|
$this->search->setSort($sf, $st === 'ASC');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set offset, limit
|
|
|
|
|
$p = max(1, intval($p));
|
|
|
|
|
$n = XSSearch::PAGE_SIZE;
|
|
|
|
|
$this->search->setLimit($n, ($p - 1) * $n);
|
|
|
|
|
|
|
|
|
|
// get the result
|
|
|
|
|
$search_begin = microtime(true);
|
|
|
|
|
$this->docs = $this->search->search();
|
|
|
|
|
$this->search_cost = microtime(true) - $search_begin;
|
|
|
|
|
|
|
|
|
|
// get other result
|
|
|
|
|
$this->count = $this->search->getLastCount();
|
|
|
|
|
$this->total = $this->search->getDbTotal();
|
|
|
|
|
|
|
|
|
|
if ($xml !== 'yes')
|
|
|
|
|
{
|
|
|
|
|
if ($this->count<1)
|
|
|
|
|
$this->expanded=$this->search->getExpandedQuery($q);
|
|
|
|
|
// try to corrected, if resul too few
|
|
|
|
|
if ($this->count < 1 || $this->count < ceil(0.001 * $this->total))
|
|
|
|
|
$this->corrected = $this->search->getCorrectedQuery();
|
|
|
|
|
// get related query
|
|
|
|
|
$this->related = $this->search->getRelatedQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gen pager
|
|
|
|
|
if ($this->count > $n)
|
|
|
|
|
{
|
|
|
|
|
$pb = max($p - 5, 1);
|
|
|
|
|
$pe = min($pb + 10, ceil($this->count / $n) + 1);
|
|
|
|
|
$this->pager = '';
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
$this->pager .= ($pb == $p) ? '<strong>' . $p . '</strong>' : '<a href="' . $this->base_url . '&p=' . $pb . '">[' . $pb . ']</a>';
|
|
|
|
|
}
|
|
|
|
|
while (++$pb < $pe);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (XSException $e)
|
|
|
|
|
{
|
|
|
|
|
$this->error = strval($e);
|
|
|
|
|
}
|
|
|
|
|
// calculate total time cost
|
|
|
|
|
$this->total_cost = microtime(true) - $total_begin;
|
|
|
|
|
|
|
|
|
|
// XML OUPUT
|
|
|
|
|
if ($xml === 'yes' && !empty($q))
|
|
|
|
|
{
|
|
|
|
|
header("Content-Type: text/xml; charset=$oe");
|
|
|
|
|
echo "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
|
|
|
|
|
echo "<xs:result count=\"$this->count\" total=\"$this->total\" cost=\"$this->total_cost\" xmlns:xs=\"http://www.xunsearch.com\">\n";
|
|
|
|
|
if ($this->error !== '')
|
|
|
|
|
echo " <error><![CDATA[" . $this->error . "]]></error>\n";
|
|
|
|
|
|
|
|
|
|
foreach ($this->docs as $doc)
|
|
|
|
|
{
|
|
|
|
|
echo " <doc index=\"" . $doc->rank() . "\" percent=\"" . $doc->percent() . "%\">\n";
|
|
|
|
|
foreach ($doc as $k => $v)
|
|
|
|
|
{
|
|
|
|
|
echo " <$k>";
|
|
|
|
|
if (is_numeric($v))
|
|
|
|
|
echo $v;
|
|
|
|
|
else
|
|
|
|
|
echo "\n <![CDATA[" . $v . "]]>\n ";
|
|
|
|
|
echo "</$k>\n";
|
|
|
|
|
}
|
|
|
|
|
echo " </doc>\n";
|
|
|
|
|
}
|
|
|
|
|
echo "</xs:result>\n";
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//搜索建议
|
|
|
|
|
function suggest($q)
|
|
|
|
|
{
|
|
|
|
|
$terms = array();
|
|
|
|
|
if (!empty($q) && strpos($q, ':') === false)
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$terms = $this->search->setCharset('UTF-8')->getExpandedQuery($q);
|
|
|
|
|
} catch (XSException $e) { }
|
|
|
|
|
}
|
|
|
|
|
return json_encode($terms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//添加新文档
|
2013-01-23 00:16:24 +00:00
|
|
|
|
//$data: 包含field和value的数组
|
2012-12-16 08:40:08 +00:00
|
|
|
|
function add($data)
|
|
|
|
|
{
|
|
|
|
|
$doc=new XSDocument;
|
|
|
|
|
$index=$this->xs->index;
|
|
|
|
|
$doc->setFields($data);
|
|
|
|
|
$index->add($doc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//更新已有文档
|
2013-01-23 00:16:24 +00:00
|
|
|
|
//$data: 包含field和value的数组
|
2012-12-16 08:40:08 +00:00
|
|
|
|
function update($data)
|
|
|
|
|
{
|
|
|
|
|
$doc=new XSDocument;
|
|
|
|
|
$index=$this->xs->index;
|
|
|
|
|
$doc->setFields($data);
|
|
|
|
|
$index->update($doc);
|
|
|
|
|
}
|
|
|
|
|
//根据主键删除对应的索引
|
|
|
|
|
function del($data,$field='')
|
|
|
|
|
{
|
|
|
|
|
$index=$this->xs->index;
|
|
|
|
|
if (empty($field))
|
|
|
|
|
$index->del($data);
|
|
|
|
|
else {
|
|
|
|
|
$index->del($data,$field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|