You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/common/library/elasticsearch/Client.php

878 lines
20 KiB

<?php
namespace app\common\library\elasticsearch;
use Elastic\Elasticsearch\ClientBuilder;
use think\Exception;
class Client
{
public $client;
const ES_HOST_NAME = '114.55.95.135:9200';
private static $instance;
/**
* @var 索引名称
*/
protected $index;
public $alias;
protected $retries = 2;
/**
* 查询参数
* @var array $queryParams
*/
protected $queryParams = [];
private $debug;
public function __construct()
{
$this->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 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]
];
}
}
$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"=>"<b style='color:red'>",
"post_tags"=>"</b>"
];
//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 "<pre>";
// 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
];
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' => [
'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
]
]
];
// 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);
}
}