westdc-core/Westdc/Metadata/Search.php

293 lines
8.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Created by PhpStorm.
* User: liujin834
* Date: 14/12/21
* Time: 上午11:11
*/
namespace Westdc\Metadata;
class Search
{
var $terms;
var $text;
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;
}
function __construct($text='')
{
require_once '/home/wlx/xunsearch/sdk/php/lib/XS.php';
$this->xs=new XS('heihe');
$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 = '';
$__ = array('q', 'm', 'f', 's', 'p', 'ie', 'oe', 'syn', 'xml','east','west','south','north','begin','end');
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
$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;
$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();
}
{
// 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);
}
//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);
}
// 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);
}
//添加新文档
//$data: 包含field和value的数组
function add($data)
{
$doc=new XSDocument;
$index=$this->xs->index;
$doc->setFields($data);
$index->add($doc);
}
//更新已有文档
//$data: 包含field和value的数组
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);
}
}
}