westdc-zf1/application/models/Search.php

284 lines
6.9 KiB
PHP
Raw Normal View History

<?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';
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='')
{
require_once '/home/wlx/xunsearch/sdk/php/lib/XS.php';
$this->xs=new XS('westdc');
$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();
}
else
{
// 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);
}
}
}