简单封装一个es类(前提是已经安装好了es组件包)
<?php
namespace app\common\controller;
use Elasticsearch\ClientBuilder;
use Elasticsearch\Common\Exceptions\BadRequest400Exception;
use think\facade\Log;
/**
* MySQL与 es 的参照对比
* mysql es
* 数据库(database) 索引(indices)
* 表(tables) 类型(types)
* 行(rows) 文档(documents)
* 字段(columns) 字段(fields)
* Class ElasticSearch
* @package app\common\controller
*/
class ElasticSearch
{
private $client;
private $host = [
'192.168.111.130:9200'
];
const INDEX = 'my_index';
public function __construct()
{
$this->client = ClientBuilder::create()->setHosts($this->host)->build();
}
/**
* 创建索引
* 相当于数据库中建库建表的操作
* @param string $index
* @param array $body
* @return bool
*/
public function createIndex(string $index = 'my_index', array $body = []): bool
{
$params = [
'index' => $index, //索引名称
'body' => [
'settings' => [ // 设置配置
'number_of_shards' => 1, //主分片数
'number_of_replicas' => 0 //主分片的副本数
],
'mappings' => [ // 设置映射
'_source' => [ // 存储原始文档
'enabled' => 'true'
],
'properties' => $body // 配置数据结构与类型
],
]
];
try {
$this->client->indices()->create($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "创建索引{$index}失败");
return false;
}
return true;
}
/**
* 删除索引(删除数据库)
* @param string $index
* @return bool
*/
public function deleteIndex(string $index = self::INDEX): bool
{
$params = [
'index' => $index
];
try {
$this->client->indices()->delete($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "删除索引{$index}失败");
return false;
}
return true;
}
/**
* 判断索引是否存在
* @param string $index
* @return bool
*/
public function indexExists(string $index = self::INDEX): bool
{
$params = ['index' => $index];
return $this->client->indices()->exists($params);
}
/**
* 查看映射
* @param string $index
* @return array
*/
public function getMapping(string $index = self::INDEX): array
{
$params = [
'index' => $index,
];
try {
return $this->client->indices()->getMapping($params);
} catch (\Exception $e) {
return json_decode($e->getMessage(), true);
}
}
/**
* 添加文档(添加一行数据)
* @param int $id
* @param array $body
* @param string $index
* @return bool
*/
public function addDos(int $id, array $body, string $index = self::INDEX): bool
{
$params = [
'index' => $index,
'id' => $id,
'body' => $body
];
try {
$this->client->index($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "新增文档{$id}失败");
return false;
}
return true;
}
/**
* 批量插入文档
* @param array $params
* @return bool
*/
public function addAllDos(array $params)
{
try {
$this->client->bulk($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "分批插入失败");
return false;
}
return true;
}
/**
* 获取文档总数(统计)
* @param string $index
* @return array|mixed
*/
public function getCountDos(string $index = self::INDEX)
{
$params = [
'index' => $index,
];
try {
return $this->client->count($params);
} catch (\Exception $e) {
return json_decode($e->getMessage(), true);
}
}
/**
* 获取文档(获取一行数据)
* @param int $id
* @param string $index
* @return array|mixed
*/
public function getDoc(int $id, string $index = self::INDEX): array
{
$params = [
'index' => $index,
'id' => $id
];
try {
return $this->client->get($params);
} catch (\Exception $e) {
return json_decode($e->getMessage(), true);
}
}
/**
* 更新文档(更新一条数据)
* @param int $id
* @param array $body
* @param string $index
* @return bool
*/
public function updateDoc(int $id, array $body, string $index = self::INDEX): bool
{
$params = [
'index' => $index,
'id' => $id,
'body' => [
'doc' => $body
]
];
try {
$this->client->update($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "更新文档{$id}失败");
return false;
}
return true;
}
/**
* 删除文档(删除一条数据)
* @param int $id
* @param string $index
* @return bool
*/
public function deleteDoc(int $id, string $index = self::INDEX): bool
{
$params = [
'index' => $index,
'id' => $id
];
try {
$this->client->delete($params);
} catch (\Exception $e) {
Log::write($e->getMessage(), "删除文档{$id}失败");
return false;
}
return true;
}
/**
* 搜索
* @param string $keywords 检索词
* @param string $index 索引名
* @param int $limit 一次显示多少条
* @param int $page 分页页码,从几开始
* @return array
*/
public function searchDoc(string $keywords, string $index = self::INDEX, int $limit = 10, int $page = 1): array
{
$offset = ((int)$page - 1) * (int)$limit;
$params = [
'index' => $index,
'body' => [
'_source' => ['id', 'title'], // 指定返回的字段
'query' => [
// 多字段匹配
// 'multi_match' => [
// 'query' => $keywords,
// 'fields' => ['title', 'content', 'keyword'],
// 'type' => 'most_fields' // most_fields 多字段匹配度更高 best_fields 完全匹配占比更高
// ],
// 单个字段匹配
// 'match' => [
// 'title' => $keywords
// ],
// 完全匹配
// 'match_phrase' => [
// 'title' => $keywords
// ],
// 联合查询
'bool' => [
'should' => [ // 相当于or
[
'match_phrase' => [
'title' => $keywords
]
],
[
'match_phrase' => [
'content' => $keywords
]
],
[
'match_phrase' => [
'keyword' => $keywords
]
],
],
// 'must' => [ // 相当于and
// [
// 'match' => [
// 'title' => $keywords
// ]
// ],
// ],
// 'should' => [ // 相当于or
// [
// 'match' => [
// 'title' => $keywords
// ]
// ],
// [
// 'match' => [
// 'content' => $keywords
// ]
// ],
// [
// 'match' => [
// 'keyword' => $keywords
// ]
// ],
// ],
// 'must_not' => [ // 相当于not
// [
// 'match' => [
// 'content' => $keywords
// ]
// ]
// ],
// 'filter' => [ // 过滤器 gt 大于;gte 大于等于;lt 小于;lte 小于等于
// 'range' => [
// 'id' => ['lt' => 20598, 'gt' => 20590]
// ]
// ],
],
],
'highlight' => [ // 搜索词高亮设置
// 'pre_tags' => "<p class='key' style='color: red;'>", // 自定义高亮样式
// 'post_tags' => "</p>",
'fields' => [ // 设置高亮的字段
'title' => (object)[],
'content' => (object)[],
'keyword' => (object)[],
]
],
// 'sort' => [['id' => ['order' => 'desc']]], // 排序,不设置会根据最高匹配度来排序
'from' => $offset, // 分页 - 从哪开始
'size' => $limit // 一次显示多少条
]
];
try {
return $this->client->search($params);
} catch (\Exception $e) {
return json_decode($e->getMessage(), true);
}
}
}
然后就可以在要用到的地方调用了,这里只写一个测试方法
<?php
namespace app\index\controller;
use app\common\controller\ElasticSearch;
use app\index\model\Articles;
use think\App;
use think\Db;
class Es extends HomeBase
{
private $es;
private $index = 'article';
public function __construct(App $app = null)
{
parent::__construct($app);
$this->es = new ElasticSearch();
}
public function test()
{
// $this->es->deleteIndex('test_ik');
// $this->create();
// $map = $this->es->getMapping($this->index);
// dump($map);
// $this->add();
// $this->get();
$this->search('测试');
}
public function create()
{
if (!$this->es->indexExists($this->index)) {
$params = [
'id' => ['type' => 'integer'],
'title' => ['type' => 'keyword'],
'keyword' => ['type' => 'keyword'],
'abstract' => ['type' => 'text'],
'content' => ['type' => 'text'],
'category_id' => ['type' => 'integer'],
'cover_map' => ['type' => 'text'],
'release_time' => ['type' => 'date'],
];
$this->es->createIndex($this->index, $params);
}
}
public function add()
{
$success = 0;
$error = 0;
$num = 500;
Articles::where(['status' => 1, 'is_del' => 0])
->field('id,title,keyword,abstract,content,category_id,cover_map,release_time')
->chunk($num, function ($articles) use (&$success, &$error, $num) {
$params = ['body' => []];
foreach ($articles as $article) {
$params['body'][] = [
'index' => [ #创建或替换
'_index' => $this->index,
'_id' => $article['id'],
],
];
$params['body'][] = $article;
}
$res = $this->es->addAllDos($params);
if ($res) {
$success += $num;
} else {
$error += $num;
}
});
echo "同步完成,成功{$success}条,失败{$error}条";
}
public function get()
{
$res = $this->es->getCountDos($this->index);
dump($res);
}
public function search($keyword)
{
$res = $this->es->searchDoc($keyword, $this->index);
dump($res);
}
}