记录一简单solr操作类
2017-04-01 阅读数:257

        solr的php使用有一个比较官方的扩展,百度搜一下会有,使用方法也给出来了,但是本人硬是搞了许久没用起来,所以索性就自己写了一个,功能不多,够自己用,用起来方便。之所以有写这个操作类的想法,是因为solr服务的所有数据访问都可以通过http请求的方式模拟出来,此操作类就是通过组装一条http请求,进而实现操作solr里的数据。操作类目前可以对solr执行新增,修改,查询三种操作,删除操作刚开始考虑到错删的情况所以没加,删除操作个人推荐还是到solr的控制台进行操作,先查询,确认数据,再删,不至于搞错,毕竟数据都是命啊……


配置文件格式:

<?php

class Conf {
	public static $solr_handle = array(
	        'product' => array('collection' => 'product', 'server' => '192.168.2.220:8983', 'pk' => 'StoreProductId'),
		'bproduct' => array('collection' => 'bproduct', 'server' => '192.168.2.220:8983', 'pk' => 'ProductId'),
		'pproduct' => array('collection' => 'pproduct', 'server' => '192.168.2.220:8983', 'pk' => 'PStoreProductId'),
		'order' => array('collection' => 'order', 'server' => '192.168.2.220:8983', 'pk' => 'OrderID'),
	);

}

操作类实现:

<?php

namespace lib;

class Solr {

	private $where = 'q=*:*';
	private $collection;
	private $action;
	private $wt = 'json'; //返回格式
	private $httpClient;
	private $host;
	private $method;
	private $data = array();
	private $body = array();
	private $contentType = '';
	private $pk;
	private $fields = '';
	private $limit = '&rows=1000&start=0';
	private $sort = '';
	public $errorMsg = '';
	private $sql;

	public function __construct($collection) {
		if (!$collection) {
			throw new \Exception("不合法的collection名称");
		}
		if (!in_array($collection, array_keys(\Conf::$solr_handle))) {
			throw new \Exception("未配置的collection名称");
		}
		$this->getNode($collection);
		$this->pk = \Conf::$solr_handle[$collection]['pk'];
		$this->collection = \Conf::$solr_handle[$collection]['collection'];
		$this->httpClient = new \Client();
	}
	
	private function getNode($collection) {
		$zookeeper = new \MyZookeeper(\Conf::$solrzookeeper);
		$liveNodes = $zookeeper->getChildren('/live_nodes');
		if (!$liveNodes) {
			throw new \Exception("没有存活的solr节点,请确认zookeeper的solr节点配置项/live_nodes信息");
		}
		$num = rand(0, count($liveNodes) - 1);
		//若从zookeeper中没有找到存活的solr节点,则使用配置文件中的host
		$this->host = explode("_", $liveNodes[$num])[0] ? : \Conf::$solr_handle[$collection]['server'];
	}
	
	public function where($column, $op, $value) {
		$this->where = trim($this->where, "q=");
		$this->where = trim($this->where, "q=*:*");
		switch ($op) {
			case '=':
				$this->where .= '+AND+' . $column . ':' . $value;
				$this->where = trim($this->where, "+AND+");
				break;
			case 'in':
				$inValue = explode(",", $value);
				$this->where .= '+AND+(';
				foreach ($inValue as $v) {
					$this->where .= $column . ':' . trim($v) . '+OR+';
				}
				$this->where = trim($this->where, "+OR+");
				$this->where .= ')';
				break;
			case '>':
				$this->where .= '+AND+' . $column . ':{' . $value . '+TO+*}';
				$this->where = trim($this->where, "+AND+");
				break;
			case '<':
				$this->where .= '+AND+' . $column . ':{*+TO+' . $value . '}';
				$this->where = trim($this->where, "+AND+");
				break;
			case '>=':
				$this->where .= '+AND+' . $column . ':[' . $value . '+TO+*]';
				$this->where = trim($this->where, "+AND+");
				break;
			case '<=':
				$this->where .= '+AND+' . $column . ':[*+TO+' . $value . ']';
				$this->where = trim($this->where, "+AND+");
				break;
			case 'like':
				$this->where .= '+AND+' . $column . ':*' . $value . '*+';
				$this->where = trim($this->where, "+AND+");
				break;
			case 'between':
				$between = explode(",", urldecode($value));
				$this->where .= '+AND+' . $column . ':[' . ($between[0] ? : '*') . '+TO+' . ($between[1]? : '*') . ']';
				$this->where = trim($this->where, "+AND+");
				break;
		}
		$this->where = trim($this->where, "AND+");
		$this->where = 'q=' . $this->where;
		return $this;
	}

	public function sort($sort, $type = 'ASC') {
		$this->sort = '&sort=' . $sort . '+' . $type;
		return $this;
	}

	public function fields($fields) {
		if (!$fields) {
			return $this;
		}
		$this->fields = '&fl=' . $fields;
		return $this;
	}

	public function limit($rows, $start = 0) {
		if (!$rows) {
			return $this;
		}
		$this->limit = '&rows=' . (int) $rows . '&start=' . $start;
		return $this;
	}

	public function query() {
		$this->action = 'select';
		$this->method = 'get';
		$this->queryPrepare();
		return $this->request();
	}

	private function queryPrepare() {
		$this->data = array();
	}

	public function add($data) {
		if (is_array(reset($data))) {
			foreach ($data as &$v) {
				if (!isset($v[$this->pk])) {
					throw new \Exception("没有找到主键");
				}
				$v['AddTime'] = date('Y-m-d H:i:s');
			}
			$this->data = json_encode($data);
		} else {
			if (!isset($data[$this->pk])) {
				throw new \Exception("没有找到主键");
			}
			$data['AddTime'] = date('Y-m-d H:i:s');
			$this->data = json_encode(array($data));
		}
		$this->action = 'update';
		$this->method = 'post';
		$this->contentType = 'application/json';
		return $this->request();
	}

	public function update($data) {
		if (!$data) {
			throw new \Exception("缺少需要更新的数据");
		}
		if ($this->where != 'q=*:*') {//带条件的更新操作
			$this->getUpdateData($data);
		} else {
			$this->getData($data);
		}
		$this->action = 'update';
		$this->method = 'post';
		$this->contentType = 'application/json';
		return $this->request();
	}

	public function setQ($q) {
		if (!$q) {
			throw new \Exception('缺少查询条件');
		}
		$this->where = 'q=' . $q;
		return $this;
	}

	/**
	 * 含有查询条件的更新
	 * @param type $data
	 * @return type
	 */
	private function getUpdateData(&$data) {
		$result = $this->fields($this->pk)->query();
		if (!$result['numFound']) {
			$this->data = json_encode(array());
			return;
		}
		$selfArr = array();
		if (isset($data[$this->pk])) {
			unset($data[$this->pk]);
		}
		foreach ($data as $key => $value) {
			$selfArr[$key] = array('set' => $value);
		}
		foreach ($result['docs'] as $k => $v) {
			$this->data[$k] = array_merge($selfArr, array(
				$this->pk => $v[$this->pk],
				'UpdateTime' => array('set' => date('Y-m-d H:i:s')
			)));
		}
		$this->data = json_encode($this->data);
	}

	private function getData(&$data) {
		if (is_array($data[0])) {
			foreach ($data as $k => $v) {
				if (!in_array($this->pk, array_keys($v))) {
					throw new \Exception("没有找到主键");
				}
				foreach ($v as $kk => $vv) {
					$this->data[$k][$kk] = $kk == $this->pk ? $vv : array('set' => $vv);
				}
				$this->data[$k]['UpdateTime'] = array('set' => date('Y-m-d H:i:s'));
			}
		} else {
			if (!in_array($this->pk, array_keys($data))) {
				throw new \Exception("没有找到主键");
			}
			foreach ($data as $k => $v) {
				$this->data[0][$k] = $k == $this->pk ? $v : array('set' => $v);
			}
			$this->data[0]['UpdateTime'] = array('set' => date('Y-m-d H:i:s'));
		}
		$this->data = json_encode($this->data);
	}

	public function delete() {
		$this->request();
	}

	public function getSql() {
		return $this->sql;
	}

	public function getBody() {
		return $this->body;
	}

	private function reset() {
		$this->body = $this->data;
		$this->data = array();
		$this->where = 'q=*:*';
		$this->fields = '';
		$this->limit = '&rows=1000&start=0';
		$this->sort = '';
	}

	public function request() {
		$this->sql = 'http://' . $this->host . '/solr/' . $this->collection . '/' . $this->action . '?' . $this->where . $this->fields . $this->sort . $this->limit . '&wt=' . $this->wt;
		$result = json_decode($this->httpClient->singleRequest($this->sql, $this->method, $this->data, '', $this->contentType), true);
		$this->reset();
		if ($result['responseHeader']['status'] !== 0) {
			throw new \Exception($result['error']['msg'] . "\n" . 'sql:' . $this->sql . "\n");
		}
		if ($this->action == 'select') {
			return $result['response'];
		}
		return true;
	}

}


        操作类支持solr集群模式的使用,因为solr集群本身会借助zookeeper,所以solr集群的各节点状态可以在zookeeper上读取到,其中涉及到的zookeeper扩展的使用可以参考我的博文http://blog.dongguagua.com/Index/detail/Id/16.html

本文中涉及到一个Client类的使用,该类为curl的操作类,用来模拟发送http请求的,读者可以将自己用的http类替换,或者直接用file_get_contents()(不推荐),以下附上该操作类。


<?php

/**
 * Description of Rest
 *
 * @author polaris
 */
class Client {

	private $options = array(
		'timeout' => 2,
		'connecttimeout' => 3,
	);

	public function __construct() {
		$this->options['timeout'] = Conf::$request_time_out ? : 2;
		$this->options['connecttimeout'] = Conf::$connect_time_out ? : 3;
	}

	/**
	 * 向一个url发起请求
	 *
	 * @param string $url 请求的url地址
	 * @param string $method 请求的http方法
	 * @param array $data 请求携带的参数
	 * @return mixed
	 */
	public function singleRequest($url, $method = 'get', $data = array(), $type = 'fields', $content_type = '') {
		$curl_handle = curl_init();
		$method = strtoupper($method);
		if (is_array($data)) {
			$data = http_build_query($data);
		}

		if ($method == 'GET' && !empty($data)) {
			$url .= stripos($url, '?') > 0 ? '&' . $data : '?' . $data;
		}
		curl_setopt($curl_handle, CURLOPT_URL, $url);
		curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->options['timeout']);
		curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $method);
		curl_setopt($curl_handle, CURLOPT_HEADER, 0);
		curl_setopt($curl_handle, CURLOPT_ENCODING, 'gzip,deflate');
		if (!empty($content_type)) {
			curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('Content-Type:' . $content_type));
		}

		if ($method != 'GET') {
			curl_setopt($curl_handle, CURLOPT_POST, true);
			curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $data);
		}

		$buffer = curl_exec($curl_handle);
		curl_close($curl_handle);

		return $buffer;
	}

}

?>


        差不多就这些,希望对刚接触solr的php开发者有些帮助。

        本文是博主个人原创,转载的朋友请注明地址,不胜感激:http://blog.dongguagua.com/Index/detail/Id/14.html

前方10米有沙发可抢!
大人,请先右上角登个录 ↑
Copyright@2017-2020 www.dongguagua.com All Right Reserived 京ICP备17025269号