client = ClientBuilder::create()->setHosts([self::ES_HOST_NAME])->build(); } private function __clone() { } public static function getInstance(){ if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * 查询条件 * @param $params * @return $this */ public function select($params = '') { $this->queryParams['select'] = str_replace(' ', '', trim($params, " ,\t\r\n")); return $this; } /** * 分页 * @param $number * @return $this */ public function from($number = 0) { $this->queryParams['from'] = $number ? ($number-1)*10 : 0; $this->queryParams['current_page'] = $number; return $this; } /** * 页码 * @param $number * @return $this */ public function size($number = 10) { $this->queryParams['size'] = $number; return $this; } /** * 批量查询 * @param $params * @return $this */ public function equal($params = []) { $this->queryParams['equal'] = $params; return $this; } /** * 批量查询 * @param $params * @return $this */ public function in($params = []) { $this->queryParams['in'] = $params; return $this; } /** * 范围查找 */ public function between($params = []) { $this->queryParams['between'] = $params; return $this; } /** * 模糊查询 * @param $params * @return $this */ public function like($params = []) { //$this->queryParams['like'][] = $params; $this->queryParams['like'] = $params; return $this; } public function orlike($params = []) { //$this->queryParams['orlike'][] = $params; $this->queryParams['orlike'] = $params; return $this; } /** * has_parent 查询(父查子) * @param $params * @return $this */ public function hasParent($params = []) { $this->queryParams['has_parent'][] = $params; return $this; } /** * has_child 查询(子查父) * @param $params * @return $this */ public function hasChild($params, $child_params = []) { $this->queryParams['has_child'] = $params; return $this; } public function order($params = []) { $this->queryParams['order'] = $params; return $this; } /** * 根据条件删除文档 * @param array $params * @return array */ public function deleteDoc($params = []) { return $this->client->deleteByQuery($params); } public function batchDelete($bulkBody = []){ $params = [ 'index' => $this->index, 'body' => $bulkBody, ]; return $this->client->bulk($params); } public function existsIndex(String $index_name) { $params = [ 'index' => $index_name ]; return $this->client->indices()->exists($params); } /** * 创建索引 */ public function createIndex(String $index_name, array $mapping = []): array { if ($this->existsIndex($index_name)) { throw new Exception('索引已存在'. $index_name); } //只能创建一次 $params = [ 'index' => $index_name, 'body' => [ 'settings' => [ 'number_of_shards' => 5, 'number_of_replicas' => 1 ], 'mappings' => $mapping ] ]; return $this->client->indices()->create($params); } /** * 删除索引 */ public function deleteIndex(String $index_name = ''): array{ $params = ['index' => $index_name]; return $this->client->indices()->delete($params); } /** * 根据id删除文档 * @param int $id * @return array */ public function deleteDocById($id = 0) { $params = [ 'index' => $this->index, 'id' => $id ]; $response = $this->client->delete($params); return $response; } /** * 组装查询条件 * @param array $params * @return $this */ private function parseQueryParams() { $queryParams = [ 'index' => $this->index, 'body' => [ 'query' => [ 'bool' => [ 'must' => [], 'filter' => [] ] ], ], 'from' => $this->queryParams['from'] ?? 0, 'size' => $this->queryParams['size'] ?? 10, 'current_page' => $this->queryParams['current_page'] ?? 1, 'track_total_hits' => true, ]; $filter = $must = $orFilter = []; if (!empty($this->queryParams['select'])) { $queryParams['_source'] = explode(',', $this->queryParams['select']); } if (!empty($this->queryParams['equal'])) { foreach ($this->queryParams['equal'] as $key => $row) { foreach ($row as $filed => $value) { $filter[] = [ 'term' => [$filed => $value] ]; } } } if (!empty($this->queryParams['in'])) { foreach ($this->queryParams['in'] as $key => $row) { foreach ($row as $filed => $value) { $filter[] = [ 'terms' => [$filed => array_values(array_unique(array_filter($value)))] ]; } } } if (!empty($this->queryParams['like'])) { foreach ($this->queryParams['like'] as $key => $row) { foreach ($row as $filed => $value) { /*$must[] = [ 'wildcard' => [$filed => '*'. $value. '*'] ];*/ $must[] = [ 'match' => [$filed => $value, ''] // 'match_phrase' => [$filed => $value] ]; } } $queryParams['body']['query']['bool']['must'] = $must; } if (!empty($this->queryParams['orlike'])) { foreach ($this->queryParams['orlike'] as $key => $row) { foreach ($row as $filed => $value) { // $orlike[] = [ // 'match_phrase' => [$filed => $value] // ]; $orlike[] = [ 'match' => [$filed => ['query' => $value, 'fuzziness' => "AUTO", 'operator' => 'or']] ]; } } $queryParams['body']['query']['bool']['must']['bool']['should'] = $orlike; } //has_child 查询(子查父) if (!empty($this->queryParams['has_child'])) { $should = []; foreach ($this->queryParams['has_child'] as $key => $row) { $queryMust = []; foreach ($row as $name => $value) { if ($name == 'category_id') { $queryMust[] = [ 'has_child' => [ 'type' => 'category', 'query' => [ 'bool' => [ 'must' => [ 'terms' => [ 'category_id' => $value ] ] ] ], ], ]; } if ($name == 'profit') { $queryMust[] = [ 'range' => [ 'profit' => [ 'gte' => $value, ] ] ]; } if ($name == 'profit_rate') { $queryMust[] = [ 'range' => [ 'profit_rate' => [ 'gte' => $value, ] ] ]; } } $should[] = [ 'bool' => [ 'must' => $queryMust ] ]; } $filter[] = [ 'bool' => [ 'should' => $should ] ]; } //has_parent 查询(父查子) if (!empty($this->queryParams['has_parent'])) { foreach ($this->queryParams['has_parent'] as $key => $row) { $queryParams['body']['query']['bool']['must'][] = [ 'has_parent' => $row ]; } } if (!empty($this->queryParams['order'])) { foreach ($this->queryParams['order'] as $key => $row) { $queryParams['body']['sort'][] = [ key($row) => [ 'order' => current($row) ] ]; } } $queryParams['body']['query']['bool']['filter'] = $filter; $this->queryParams = $queryParams; return $this; } /** * @param bool $isTotal isTotal=true时, 返回总数 * @return array|string */ public function query($isTotal = false) { try { $this->parseQueryParams(); $this->queryParams['body']['highlight'] = [ "fields"=>[ "goods_name" => new \stdClass(), "goods_no" => new \stdClass(), ], "pre_tags"=>"", "post_tags"=>"" ]; //dd($this->queryParams); if ($this->debug) { return \GuzzleHttp\json_encode($this->queryParams); } if ($isTotal === true) { unset( $this->queryParams['from'], $this->queryParams['size'], $this->queryParams['_source'] ); $count = $this->client->count($this->queryParams); return (int)$count['count']; } if (!empty($this->queryParams)) { //高亮 $result = $this->client->search($this->queryParams); $data = [ 'current_page' => 1, 'data' => [], 'last_page' => 0, 'per_page' => $this->queryParams['size'], 'total' => 0, ]; if (isset($result['hits']) && !empty($result['hits'])) { $list = $result['hits']['hits']; // echo "
"; // print_r($list); // exit(); $arr = []; foreach ($list as $key => &$value) { $value['_source']['highlight_goods_name'] = isset($value['highlight']['goods_name'][0]) ? $value['highlight']['goods_name'][0] : (isset($value['highlight']['goods_no'][0]) ? $value['highlight']['goods_no'][0] : ""); $arr[] = $value['_source']; } $data['current_page'] = $this->queryParams['current_page']; $data['data'] = $arr; $data['last_page'] = ceil($result['hits']['total']['value'] / $this->queryParams['size']); $data['per_page'] = $this->queryParams['size']; $data['total'] = $result['hits']['total']['value']; } return $data; } } catch (\Exception $e) { $msg = $e->getMessage(); //$msg = '服务器开小差了~'; throw new Exception($msg); } } /** * 添加文档 * @param $id * @param $doc ['id'=>100, 'title'=>'phone'] * @param string $index_name * @param string $type_name */ public function addDoc($id, $doc, string $type_name = '_doc') { $params = [ 'index' => $this->index, 'type' => $type_name, 'id' => $id, 'body' => $doc ]; return $this->client->index($params); } /** * 添加子文档 * @param $id * @param $doc * @param string $type_name */ public function addChildDoc($id, $parent_id, $doc, string $type_name = '_doc') { $params = [ 'index' => $this->index, 'type' => $type_name, 'id' => $id, 'routing' => $parent_id,//与父文档在同一个分区 'body' => $doc ]; // var_dump($params); // exit; return $this->client->index($params); } public function getIndex() { return $this->index; } /** * 返回ES实例 */ public static function setEs($index = '') { $class = get_called_class(); if (!self::$instance || !self::$instance instanceof $class) { self::$instance = new static(); } if ($index) { self::$instance->index = $index; } return self::$instance; } protected function settings() { return [ 'number_of_shards' => 1, 'number_of_replicas' => 0, 'analysis' => [ 'analyzer' => [ 'ik' => [ 'tokenizer' => 'ik_max_word' ] ] ], ]; // return [ // 'number_of_shards' => 1, // 'number_of_replicas' => 0, // 'analysis' => [ // 'analyzer' => [ // 'default' => [ // 'type' => 'ik_smart' // ] // ] // ], // ]; } /** * 判断文档存在 * @param int $id * @param string $type_name * @return bool */ public function existsDoc(int $id = 1, string $type_name = '_doc'): bool { $params = [ 'index' => $this->index, 'type' => $type_name, 'id' => $id ]; return $this->client->exists($params); } /** * 获取文档 * @param int $id * @param string $index_name * @param string $type_name * @return array */ public function getDoc(int $id = 1, string $type_name = '_doc'): array { $params = [ 'index' => $this->index, 'type' => $type_name, 'id' => $id ]; return $this->client->get($params); } /** * 更新文档 * @param int $id * @param string $index_name * @param string $type_name * @param array $body * @return array */ public function updateDoc(int $id = 1, array $body = [], string $type_name = '_doc'): array { // 可以灵活添加新字段,最好不要乱添加 $params = [ 'index' => $this->index, 'type' => $type_name, 'id' => $id, 'body' => $body ]; return $this->client->update($params); } /** * 搜索文档:分页,排序,权重,过滤 * @param string $index_name * @param string $type_name * @param array $body * @return array */ public function searchDoc(array $body = [], string $type_name = "_doc"): array { $params = [ 'index' => $this->index, 'type' => $type_name, 'body' => $body ]; return $this->client->search($params); } /** * @return bool * @throws Exception */ public function createIndexNew($mapping) { try { $params = [ 'index' => $this->index ]; $check = $this->indices()->exists($params); if ($check->getStatusCode() == 200) { throw new Exception('index: ' . $this->index . ' already exists'); } $params = [ 'index' => $this->index, 'body' => [ 'settings' => $this->settings(), 'mappings' => [ '_source' => [ 'enabled' => true, ], 'properties' => $mapping['properties'] ] ] ]; //dd($params); $result = $this->indices()->create($params); return $result['acknowledged'] === true; } catch (\Exception $e) { throw new Exception($e->getMessage()); } } /** * 删除索引 * * @return bool * @throws Missing404Exception */ public function deleteIndexNew() { try { $params = [ 'index' => $this->index ]; $check = $this->indices()->exists($params); if (!$check) { return true; } $result = $this->indices()->delete([ 'index' => $this->index ]); return $result['acknowledged'] === true; } catch (Missing404Exception $e) { throw new Missing404Exception('no such index ' . $this->index); } } /** * 批量写入 * type 1.增加/修改 2.删除 * $data = [ * ['id' => 1, 'name' => 'llf', 'age' => 30], * ['id' => 1, 'name' => 'llf', 'age' => 30], * ['id' => 1, 'name' => 'llf', 'age' => 30], * ['id' => 1, 'name' => 'llf', 'age' => 30], * ]; * @param array $data */ public function doBulkDocument($type = 1,$data = []) { try { $params = ['body' => []]; if($type == 1){ foreach ($data as $key => $row) { $params['body'][] = [ 'index' => [ '_index' => $this->index, '_id' => $row['info_id'].'-'.$row['info_type'] ] ]; $params['body'][] = $row; if (($key+1)%10000 == 0) { $this->client->bulk($params); $params = ['body' => []]; } } }else{ foreach ($data as $key => $row) { $params['body'][] = [ 'delete' => [ '_index' => $this->index, '_id' => $row['info_id'].'-'.$row['info_type'] ] ]; } } if (!empty($params['body'])) { $this->client->bulk($params); return true; } } catch (\Exception $e) { throw new Exception($e->getMessage()); } } /** * 更新索引 * @return array @todo */ public function updateIndex($mappings) { $putParams = [ 'index' => $this->index, //'type' => '_doc', 'body' => [ 'properties' => $mappings ] ]; return $this->indices()->putMapping($putParams); } /** * 方便调试, 直接返回拼接的query * @return $this */ public function setDebug() { $this->debug = true; return $this; } private function indices() { return $this->client->indices(); } public function analyze($text = '') { $params = [ 'index' => $this->index, 'body' => [ 'analyzer' => 'ik_smart', 'text' => $text ] ]; return $this->indices()->analyze($params); } public function update($id = 0, $updateParams = []) { $params = [ 'index' => $this->index, 'id' => $id, 'body' => [ 'doc' => $updateParams ] ]; return $this->client->update($params); } }