<?php
class PsElasticSearch
{
private $client;
private static $instance;
private $index_name_prefix;
private function __construct($config)
{
include(VENDOR_PATH.'autoload.php');
if(empty($config)){
$config = array(
'host' => [ELASTICSEARCH_HOST . ':' . ELASTICSEARCH_PORT],//地址和端口配置
'prefix' => 'agentmanage'//chinabm
);
}
$this->index_name_prefix=$config['prefix'];
$this->client = \Elasticsearch\ClientBuilder::create()
->setHosts($config['host'])
->build();
}
static public function getInstance($config=[])
{
if (!self::$instance instanceof self) {
self::$instance = new self($config);
}
return self::$instance;
}
// 创建索引
public function create_index($index_name)
{ // 只能创建一次
$index_name=$this->index_name_prefix.'_'.$index_name;
$params = [
'index' => $index_name,
'body' => [
'settings' => [
'number_of_shards' => 5,
'number_of_replicas' => 0
]
]
];
try {
return $this->client->indices()->create($params);
}catch (Exception $e) {
$msg = $e->getMessage(); $msg = json_decode($msg, true); return $msg; } } // 删除索引 public function delete_index($index_name = 'test_ik') { $index_name=$this->index_name_prefix.'_'.$index_name; $params = ['index' => $index_name]; $response = $this->client->indices()->delete($params); return $response; } // 创建文档模板 public function create_mappings($index_name, $type_name, $properties) { $index_name=$this->index_name_prefix.'_'.$index_name;// $properties=[// 'id' => [// 'type' => 'integer', // 整型// ],// 'title' => [// 'type' => 'text', // 字符串型// ],// 'content' => [// 'type' => 'text',// ],// 'price' => [// 'type' => 'integer'// ]// ]; $params = [ 'index' => $index_name, 'type' => $type_name, 'body' => [ $type_name => [ '_source' => [ 'enabled' => true ], 'properties' => $properties ] ] ]; $response = $this->client->indices()->putMapping($params); return $response; } // 查看映射 public function get_mapping($index_name, $type_name) { $index_name=$this->index_name_prefix.'_'.$index_name; $params = [ 'index' => $index_name, 'type' => $type_name ]; $response = $this->client->indices()->getMapping($params); return $response; } // 添加文档 public function add_doc($id, $doc, $index_name = 'test_ik', $type_name = 'goods') { $index_name=$this->index_name_prefix.'_'.$index_name; $params = [ 'index' => $index_name, 'type' => $type_name, 'id' => $id, 'body' => $doc ]; $response = $this->client->index($params); return $response; } // 判断文档存在 public function exists_doc($id = 1, $index_name = 'test_ik', $type_name = 'goods') { $index_name=$this->index_name_prefix.'_'.$index_name; $params = [ 'index' => $index_name, 'type' => $type_name, 'id' => $id ]; $response = $this->client->exists($params); return $response; } // 获取文档 public function get_doc($id = 1, $index_name = 'test_ik', $type_name = 'goods') { $index_name=$this->index_name_prefix.'_'.$index_name; $params = [ 'index' => $index_name, 'type' => $type_name, 'id' => $id ]; $response = $this->client->get($params); return $response; } // 更新文档 public function update_doc($id, $doc, $index_name = 'test_ik', $type_name = 'goods') { $index_name=$this->index_name_prefix.'_'.$index_name; // 可以灵活添加新字段,最好不要乱添加 $params = [ 'index' => $index_name, 'type' => $type_name, 'id' => $id, 'body' => [ 'doc' => $doc ] ]; $response = $this->client->update($params); return $response; } // 删除文档 public function delete_doc($id = 1, $index_name = 'test_ik', $type_name = 'goods') { $index_name=$this->index_name_prefix.'_'.$index_name; $params = [ 'index' => $index_name, 'type' => $type_name, 'id' => $id ]; $response = $this->client->delete($params); return $response; } /*模糊查询文档 (分页,排序,权重,过滤) * @param array $data=['key'=>['value','minimum_match']] 搜索字段数组 minimum_match 默认为100% * @param array $sort=['key'=>['order'=>'desc']] 排序 * @param string $index_name 索引名 * @param string $type_name 索引表名 * @param int $from offset * @param int $size 分页大小 * */ public function search_doc($data, $sort = [], $index_name = "test_ik", $type_name = "goods", $from = 0, $size = 10) { if (!is_array($data)) return; $index_name=$this->index_name_prefix.'_'.$index_name; $field = key($data); $params = [ 'index' => $index_name, 'type' => $type_name, 'body' => [ 'query' => [ 'match' => [ $field => [ 'query' => $data[$field][0], 'minimum_should_match' => !empty($data[$field][1]) ? $data[$field][1] : '100%' ] ] ], 'sort' => $sort, 'from' => $from, 'size' => $size ] ]; $results = $this->client->search($params);// $maxScore = $results['hits']['max_score'];// $score = $results['hits']['hits'][0]['_score'];// $doc = $results['hits']['hits'][0]['_source']; return $results; } /*模糊多字段查询文档 (分页,排序,权重,过滤) * @param array $data=['field1,field2 '=>'value'] 搜索字段数组 * @param array $sort=['key'=>['order'=>'desc']] 排序 * @param string $index_name 索引名 * @param string $type_name 索引表名 * @param int $from offset * @param int $size 分页大小 * */ public function multi_search_doc($data, $sort = [], $index_name = "test_ik", $type_name = "goods", $from = 0, $size = 10) { if (!is_array($data)) return; $index_name=$this->index_name_prefix.'_'.$index_name; $field = key($data); $field_arr = explode(",", $field); $params = [ 'index' => $index_name, 'type' => $type_name, 'body' => [ 'query' => [ 'multi_match' => [ 'query' => $data[$field], 'type' => "best_fields",// 我们希望完全匹配的文档占的评分比较高,则需要使用best_fields,希望越多字段匹配的文档评分越高,就要使用most_fields,希望这个词条的分词词汇是分配到不同字段中的,那么就使用cross_fields 'fields' => $field_arr, 'tie_breaker' => 0.3 // 意思就是完全匹配"中国"的文档评分会比较靠前,如果只匹配中国的文档评分乘以0.3的系数,这方面的详细解答,请阅读:http://www.cnblogs.com/yjf512/p/4897294.html ] ], 'sort' => $sort, 'from' => $from, 'size' => $size ] ]; $results = $this->client->search($params);// $maxScore = $results['hits']['max_score'];// $score = $results['hits']['hits'][0]['_score'];// $doc = $results['hits']['hits'][0]['_source']; return $results; } /* * bool联合查询: must,should,must_not * must: 文档必须完全匹配条件; should: should下面会带一个以上的条件,至少满足一个条件,这个文档就符合should; must_not: 文档必须不匹配条件 * @param array $data=['must'=>['key1|key1,key2'=>['value1|[value1,value2]','term|terms|match|multi_match|match_phrase|range|wildcard|regexp|prefix'],'key2'=>[]],'should'=>[],'must_not'=>[]] 搜索字段数组 参考 https://www.cnblogs.com/ghj1976/p/5293250.html * @param array $sort=['key'=>['order'=>'desc']] 排序 * @param string $index_name 索引名 * @param string $type_name 索引表名 * @param int $from offset * @param int $size 分页大小 * */ public function bool_search_doc($data, $sort = [], $index_name = "test_ik", $type_name = "goods",$paginate=0,$page = 0, $size = 0) { //$index_name=$this->index_name_prefix.'_'.$index_name; $config = array(); $size = empty($size) ?intval($config['list_rows']):intval($size); if (!is_array($data)) return; $page = empty($page)?$_REQUEST['page']:$page; $page = empty($page) || intval($page) < 1 ? 1 : intval($page); $from=($page - 1) * $size; $params = [ 'index' => $index_name, 'type' => $type_name, 'body' => [ 'query' => $data, 'sort' => $sort, 'from' => $from, 'size' => $size ] ]; $results = $this->client->search($params); if (!$results) return; $results = [ 'took' => $results['took'], 'total' => $results['hits']['total'], 'list' => array_column($results['hits']['hits'], '_source', '_id') ]; if($paginate){ $results['page']=$this->paginate($size,false,$results)->render(); } return $results; } public function paginate($listRows = null, $simple = false,$result,$config = []){ return; $config =array(); $listRows = $listRows ?: $config['list_rows']; $class = false !== strpos($config['type'], '\\') ? $config['type'] : '\\think\\paginator\\driver\\' . ucwords($config['type']); $page = isset($config['page']) ? (int) $config['page'] : call_user_func([ $class, 'getCurrentPage', ], $config['var_page']); $page = empty($page) || intval($page) < 1 ? 1 : intval($page); $config['path'] = isset($config['path']) ? $config['path'] : call_user_func([$class, 'getCurrentPath']); $paginator= $class::make($result, $listRows, $page, $result['total'], $simple, $config); return $paginator; }}
public function elasticSearch(){
import("tool.PsElasticSearch", EXTEND_PATH);
$es = \PsElasticSearch::getInstance();
//新增索引
//$result=$es->create_index('test_ik');
//删除索引
//$result=$es->delete_index('test_ik');
//创建模板
// $properties=[
// 'id' => [
// 'type' => 'integer', // 整型
// ],
// 'title' => [
// 'type' => 'text', // 字符串型
// ],
// 'content' => [
// 'type' => 'text',
// ],
// 'price' => [
// 'type' => 'integer'
// ]
// ];
//$result=$es->create_mappings('test_ik','goods',$properties);
//添加文档
/*$docs = [];
$docs[] = ['id'=>1,'title'=>'苹果手机','content'=>'苹果手机,很好很强大。','price'=>1000];
$docs[] = ['id'=>2,'title'=>'华为手环','content'=>'荣耀手环,你值得拥有。','price'=>300];
$docs[] = ['id'=>3,'title'=>'小度音响','content'=>'智能生活,快乐每一天。','price'=>100];
$docs[] = ['id'=>4,'title'=>'王者荣耀','content'=>'游戏就玩王者荣耀,快乐生活,很好很强大。','price'=>998];
$docs[] = ['id'=>5,'title'=>'小汪糕点','content'=>'糕点就吃小汪,好吃看得见。','price'=>98];
$docs[] = ['id'=>6,'title'=>'小米手环3','content'=>'秒杀限量,快来。','price'=>998];
$docs[] = ['id'=>7,'title'=>'iPad','content'=>'iPad,不一样的电脑。','price'=>2998];
$docs[] = ['id'=>8,'title'=>'中华人民共和国','content'=>'中华人民共和国,伟大的国家。','price'=>19999];
foreach ($docs as $k => $v) {
$result = $es->add_doc($v['id'],$v);
}
*/
//查看文档
// $result = $es->get_doc(1,'test_ik','goods');
// print_r($result);
//$result = $es->get_doc(2,'test_ik','goods');
//print_r($result);die;
//更新文档
// $doc=['title'=>'苹果手机2','content'=>'苹果手机,很好很强大2。','price'=>10002];
// $result = $es->update_doc(1,$doc,'test_ik','goods');
//删除文档
//$result = $es->delete_doc(1,'test_ik','goods');
//print_r($result);
//判断文档存在
$result = $es->exists_doc(1, 'test_ik', 'goods');
//单字段搜索关键字
$result = $es->search_doc(['title' => ['手环 小']], [], 'test_ik', 'goods');
//print_r($result);die;
//多字段搜索关键字
//$result = $es->multi_search_doc(['title,content'=>'手机'],[],'test_ik','goods');
//print_r($result);die;
//多条件组合查询
$data = [
'must' => ['title' => ['王者', 'match'], 'content' => ['游戏', 'match'], 'price' => [['gte' => 990], 'range']]
];
$result = $es->bool_search_doc($data, [], 'test_ik', 'goods');
print_r($result);
die;
}