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

872 lines
19 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;
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;
return $this;
}
public function 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
];
$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();
// 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);
if (!empty($result['hits']['hits'])) {
$return = [];
foreach ($result['hits']['hits'] as $row) {
$return[] = $row['_source'];
}
return $return;
} else {
return [];
}
}
// } 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);
}
}