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.
900 lines
21 KiB
900 lines
21 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 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"=>"<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
|
|
];
|
|
// 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);
|
|
}
|
|
}
|
|
|