前言:
原文地址:
http://www.cnblogs.com/JimmyBright/p/7156085.html
前面在配置完成Solr服务之后,在浏览器上可以打开Solr的管理界面,这个界面几乎包含了Solr的所有功能,如何反应到我们的PHP里边呢?很多人或许查到需要再安装一个php-solr-client,用于php和java的solr服务器通信,研究了半天没弄明白怎么做,反正是很麻烦而且似乎很多余。
1:思路:
注意看Solr的管理界面上,你或许有以下发现。
上面框框中有一个url地址,把这个地址复制,然后放在浏览器的地址栏,果然如所想一样,返回了结果集。市面上有很多Solr教程,厚厚的一本书,里边讲解肯定很全面,我们没时间看,怎么能最快解决问题就怎么做。
只要浏览器上能出结果,很自然就想到,Solr这是对外公开了一套api嘛,我们完全可以用php的curl做到这一点,浏览器能做到的,curl肯定也可以。
这里写了一个简单的CURL请求方法
private function getCurl($url){ $curl = curl_init(); curl_setopt($curl, CURLOPT_URL,$url); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $data = curl_exec($curl) ; curl_close($curl); return json_decode($data,true); }
实验一下,和预期的结果完全一样,所以下面我们就用这个思路去对接php和solr。
2:使用PHP操作Solr查询
对应Solr管理界面上的Query栏目下,我们要搞清楚这些字段的意义,然后就能用php操作整个搜索过程了
图中q、fq、sort、fl、df等,这些字段都是搜索用的字段,我们只要搞清楚这些字段意义就可以写php代码了。
字段的意义网上有很多,这个链接都有介绍了
http://blog.csdn.net/zmken497300/article/details/52817825
3:使用PHP操作Solr建立索引
搜索已经有思路去解决了,还有一个关键的问题要解决,Solr是对关联的数据库建立索引,再对索引进行搜索
。很显然数据库任何时间都会变更,所以要让Solr能不间断的重建索引才能搜索到最新的结果集。
管理界面中有一个Dataimport选项,点开可以手动重建索引,我们没有看到类似Query上的查询有一个
URL,我们很希望有这一个东西,这样就能用curl,程序自动重建索引。
按照前面的思路,我们有理由相信,Solr肯定已经有这样的api。
把浏览器设置调试模式
当我点下Execute按钮的时候,看到下面网络请求果然发出了一条url,复制这个url到浏览器,和想象的一样,自动重建了索引并返回了结果打印到浏览器上。
到此为止,已经基本都解决了PHP操作Solr的技术问题,可以预见,完成一个简单的搜索功能,不会再出现技术问题了吧。
下面附上一段PHP代码,操作Solr
1 class SolrClient 2 { 3 public $query_url=''; 4 public $import_url=''; 5 private $q='q=*:*'; 6 private $fq=''; 7 private $sort=''; 8 private $rows='rows=10&start=0'; 9 private $fl=''; 10 private $raw_query=''; 11 public $hl_str=''; 12 13 function __construct($core) 14 { 15 $host=Yii::$app->params['solr_host']; 16 $this->query_url=sprintf("%s/solr/%s/select?indent=on&wt=json&",$host,$core); 17 $this->import_url=sprintf("%s/solr/%s/dataimport?indent=on&wt=json&command=full-import&verbose=false&clean=true&commit=true&optimize=false&core=crm&name=dataimport",$host,$core); 18 } 19 public function setQuery(array $query){ 20 $q_str=[]; 21 foreach ($query as $k=>$v) { 22 if(!empty($v)){ 23 $q_str[]=urlencode($k).':'.urlencode($v); 24 } 25 } 26 if(!empty($q_str)){ 27 $this->q='q='.implode(urlencode(' OR '),$q_str); 28 } 29 } 30 public function setFilterQuery(array $query){ 31 $q_str=[]; 32 foreach ($query as $k=>$v) { 33 $q_str[]='fq='.urlencode($k).':'.urlencode($v); 34 } 35 $this->fq=implode('&',$q_str); 36 } 37 public function setRows($start,$rows){ 38 $this->rows=sprintf('rows=%s&start=%s',$rows,$start); 39 } 40 public function setHighLight(array $fields,$hlpre,$hlpost){ 41 $hl_fl=[]; 42 foreach ($fields as $field) { 43 $hl_fl[]=$field; 44 } 45 $this->hl_str=sprintf("hl.fl=%s&hl.simple.post=%s&hl.simple.pre=%s&hl=on",implode(',',$hl_fl),urlencode($hlpost),urlencode($hlpre)); 46 } 47 public function setFl(array $fields){ 48 $hl_fl=[]; 49 foreach ($fields as $field) { 50 $hl_fl[]=$field; 51 } 52 $this->fl='fl='.implode(',',$hl_fl); 53 } 54 public function setRawQuery(array $params){ 55 $raw=[]; 56 foreach ($params as $k=>$v) { 57 $raw[]=$k.'='.$v; 58 } 59 $this->raw_query=implode('&',$raw); 60 } 61 public function sortQuery($field,$sort){ 62 $this->sort= "sort=".$field.urlencode(' ').$sort; 63 } 64 65 /** 66 * 搜索查询 67 * @return mixed 68 */ 69 public function search(){ 70 $this->query_url.=$this->q; 71 !empty($this->fq)&&$this->query_url.='&'.$this->fq; 72 !empty($this->sort)&&$this->query_url.='&'.$this->sort; 73 !empty($this->rows)&&$this->query_url.='&'.$this->rows; 74 !empty($this->fl)&&$this->query_url.='&'.$this->fl; 75 !empty($this->raw_query)&&$this->query_url.='&'.$this->raw_query; 76 !empty($this->hl_str)&&$this->query_url.='&'.$this->hl_str; 77 return $this->getCurl($this->query_url); 78 } 79 80 /** 81 * 全量重构索引 82 * @return mixed 83 */ 84 public function index(){ 85 return $this->getCurl($this->import_url); 86 } 87 private function getCurl($url){ 88 $curl = curl_init(); 89 curl_setopt($curl, CURLOPT_URL,$url); 90 curl_setopt($curl, CURLOPT_HEADER, 0); 91 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 92 $data = curl_exec($curl) ; 93 curl_close($curl); 94 return json_decode($data,true); 95 } 96 97 }
search方法就是用来发起CURL的搜索命令,当然在这之前,你需要使用其他方法设置你的查询条件什么的。
index方法就是用来发起CURL的重建索引命令,把这个方法放在crontab 定时任务里,就可以定时重建索引,我这里是全量重建索引,如果你的数据量很大,对新内容的搜索时效性也要求很高,那么可以使用增量索引,怎么做呢?看下管理界面,操作一下,然后调试模式抓取发出的请求连接,简单吧。
结束:
至此,就可以完成一个企业级的搜索服务了,下面贴上我给前端写的一个搜索接口,仅供参考!
1 public function actionSearch(){ 2 $input = $this->getParam('input'); 3 $page = $this->getParam('page')-1; 4 empty($page)&&$page=0; 5 $pageLength=200; 6 $page<0&&$page=0; 7 $startRow = $page*$pageLength; 8 $params=['content_txt'=>$input,'title'=>$input]; 9 $solr = new SolrClient('crm'); 10 $solr->setQuery($params); 11 $solr->setRows($startRow,$pageLength); 12 $solr->setFl(['id','title','create_time','content','content_txt','keyword','description','sid','mask_status','type','article_type','item_type','sequence']); 13 $solr->setHighLight(['title','content_txt'],"<b style='color: #f15353;'>","</b>"); 14 $data = $solr->search(); 15 $response=&$data['response']; 16 $highlighting=&$data['highlighting']; 17 $docs = &$response['docs']; 18 empty($docs) && $this->jsonReturn(0,'搜索成功',['totalpage'=>0,'totalcount'=>0,'pagesize'=>$pageLength, 'list'=>[]]); 19 foreach ($docs as &$doc) { 20 $id = $doc['id']; 21 $hlItem = $highlighting[$id]; 22 $doc['content']=mb_substr($doc['content_txt'],0,200); 23 if(!empty($hlItem)){ 24 if(!empty($hlItem['title'])){ 25 if(!empty($hlItem['title'][0])){ 26 $doc['title']=$hlItem['title'][0]; 27 } 28 } 29 if(!empty($hlItem['content_txt'])){ 30 if(!empty($hlItem['content_txt'][0])){ 31 $doc['content']=$hlItem['content_txt'][0]; 32 } 33 } 34 } 35 unset($doc['content_txt']); 36 } 37 $res=[ 38 'totalpage'=>ceil($response['numFound']/$pageLength), 39 'totalcount'=>$response['numFound'], 40 'pagesize'=>$pageLength, 41 'list'=>$response['docs'], 42 ]; 43 $this->jsonReturn(0,'搜索成功。',$res); 44 }
然后附上一个简单粗糙的demo页面