php
复制代码
<?php
namespace Tests\Unit;
use Elasticsearch\ClientBuilder;
use Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost;
use Elasticsearch\Common\Exceptions\ElasticsearchException;
use Elasticsearch\Common\Exceptions\Missing404Exception;
use Exception;
use PHPUnit\Framework\TestCase;
class ExampleTest extends TestCase
{
//创建索引
public function testExample()
{
// 创建客户端时确保使用同步模式
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200'])
->setRetries(2)
->build();
$indexName = 'your_index';
try {
// 尝试创建索引(如果不存在)
try {
$client->indices()->create([
'index' => $indexName,
'body' => [
'settings' => [
'number_of_shards' => 1,
'number_of_replicas' => 0
]
]
]);
echo "索引 '$indexName' 创建成功\n";
} catch (ElasticsearchException $e) {
// 如果索引已存在,Elasticsearch会抛出异常,这里忽略这个异常
if (strpos($e->getMessage(), 'resource_already_exists_exception') === false) {
// 不是索引已存在的异常,需要重新抛出
throw $e;
}
echo "索引 '$indexName' 已存在\n";
}
// 执行搜索操作
try {
$response = $client->search([
'index' => $indexName,
'body' => [
'query' => ['match_all' => new \stdClass()]
]
]);
// 处理成功响应
echo "搜索成功,找到 " . $response['hits']['total']['value'] . " 条结果\n";
} catch (Missing404Exception $e) {
// 处理404错误(资源不存在)
echo "404错误:" . $e->getMessage() . "\n";
}
} catch (CouldNotConnectToHost $e) {
// 处理连接失败(ES服务未启动或地址错误)
echo "连接失败:请检查ES服务是否启动,地址是否正确\n";
echo "错误详情:" . $e->getMessage() . "\n";
} catch (ElasticsearchException $e) {
// 处理其他ES相关错误
echo "ES错误:" . $e->getMessage() . "\n";
} catch (Exception $e) {
// 处理自定义异常或其他错误
echo "错误:" . $e->getMessage() . "\n";
}
}
//获取索引列表
public function testExample2(){
// 创建客户端时确保使用同步模式
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200'])
->setRetries(2)
->build();
//删除索引
// $client->indices()->delete(['index' => 'your_index']);
$result = $client->cat()->indices([
'format' => 'json'
]);
echo "索引列表:\n";
foreach ($result as $index) {
echo "索引名:{$index['index']},状态:{$index['health']},文档数:{$index['docs.count']}\n";
}
}
public function testDocMethod(){
// 创建客户端时确保使用同步模式
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200'])
->setRetries(2)
->build();
// 2. 定义要插入的文档数据
$document = [
'name' => '张三',
'age' => 30,
'email' => 'zhangsan@example.com',
'hobbies' => ['篮球', '阅读'],
'created_at' => date('Y-m-d H:i:s')
];
// 3. 配置插入参数
$params = [
'index' => 'users', // 目标索引名(若不存在,默认会自动创建)
'id' => 'user_1001', // 可选:手动指定文档ID,不指定则ES自动生成
'body' => $document // 文档内容
];
$response = $client->index($params);
if ($response['result'] === 'created') {
echo "文档插入成功!\n";
echo "文档ID:{$response['_id']}\n";
echo "索引:{$response['_index']}\n";
echo "版本号:{$response['_version']}\n"; // 新文档版本为1
} elseif ($response['result'] === 'updated') {
// 若指定了已存在的ID,则会更新文档,result为'updated'
echo "文档更新成功!\n";
}
}
public function testDocSearch(){
// 创建客户端时确保使用同步模式
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200'])
->build();
// ->setRetries(2);
// 基础查询:匹配所有文档
$params = [
'index' => "users",
'body' => [
'query' => [
'match_all' => new \stdClass() // match_all 查询匹配所有文档
],
'size' => 10, // 最多返回10条结果(默认10)
'from' => 0 // 从第0条开始(用于分页)
]
];
// 简单查询:匹配 name 字段包含"张三"的文档
// $params = [
// 'index' => $index,
// 'body' => [
// 'query' => [
// 'match' => [
// 'name' => '张三' // 匹配 name 字段包含"张三"的文档
// // 多字段匹配:'multi_match' => ['query' => '关键词', 'fields' => ['name', 'email']]
// ]
// ]
// ]
// ];
// 精确匹配(term/terms)
//term:精确匹配单个值(适合数字、日期、keyword 类型字段)。
//terms:匹配多个值中的任意一个。
//
// // 精确匹配 age=30
// $params = [
// 'body' => [
// 'query' => [
// 'term' => ['age' => 30]
// ]
// ]
// ];
//
//// 匹配 age 为 25、30、35 中的任意一个
// $params = [
// 'body' => [
// 'query' => [
// 'terms' => ['age' => [25, 30, 35]]
// ]
// ]
// ];
// 范围查询(range)
//匹配字段值在指定范围内的文档(适合数字、日期):
// $params = [
// 'body' => [
// 'query' => [
// 'range' => [
// 'age' => [
// 'gte' => 20, // >=20
// 'lte' => 40, // <=40
// // 其他符号:gt(>), lt(<)
// ]
// ]
// ]
// ]
// ];
// 组合条件查询(bool)
//通过 must(必须满足)、should(满足其一)、must_not(必须不满足)组合多条件:
// $params = [
// 'body' => [
// 'query' => [
// 'bool' => [
// 'must' => [
// ['match' => ['hobbies' => '篮球']] // 必须喜欢篮球
// ],
// 'filter' => [
// ['range' => ['age' => ['gt' => 25]]] // 年龄>25(不影响评分)
// ],
// 'must_not' => [
// ['term' => ['status' => '禁用']] // 排除禁用用户
// ],
// 'should' => [
// ['match' => ['city' => '北京']],
// ['match' => ['city' => '上海']] // 至少满足一个城市
// ]
// ]
// ]
// ]
// ];
// 排序与分页
// $params = [
// 'body' => [
// 'query' => [/* ... */],
// 'sort' => [
// ['age' => ['order' => 'desc']], // 按 age 降序
// ['created_at' => ['order' => 'asc']] // 再按创建时间升序
// ],
// 'from' => 10, // 从第10条开始(跳过前10条)
// 'size' => 10 // 返回10条
// ]
// ];
//模糊查询
// $params = [
// 'index' => $indexName,
// 'body' => [
// 'query' => [
// 'fuzzy' => [
// 'name' => [ // 要查询的字段(通常是 text 或 keyword 类型)
// 'value' => $keyword, // 关键词
// 'fuzziness' => 'AUTO', // 允许的模糊程度(默认 AUTO)
// 'prefix_length' => 1, // 前缀不允许模糊的字符数(前1个字符必须准确)
// 'max_expansions' => 10 // 最多匹配的候选词数量(避免性能问题)
// ]
// ]
// ]
// ]
// ];
//高亮查询
// $params = [
// 'index' => $indexName,
// 'body' => [
// 'query' => [
// 'match' => [
// 'content' => $keyword // 在 content 字段中匹配关键词
// ]
// ],
// 'highlight' => [
// 'fields' => [
// 'content' => new \stdClass() // 对 content 字段启用高亮(使用默认配置)
// ],
// 'pre_tags' => ['<em class="highlight">'], // 高亮前缀标签
// 'post_tags' => ['</em>'] // 高亮后缀标签
// ]
// ]
// ];
//最大值查询
// $params = [
// 'index' => $indexName,
// 'body' => [
// 'size' => 0, // 不需要返回原始文档,只关心聚合结果
// 'aggs' => [ // 定义聚合
// 'max_' . $field => [ // 聚合名称(自定义,用于后续解析结果)
// 'max' => [
// 'field' => $field // 要计算最大值的字段
// ]
// ]
// ]
// ]
// ];
//分组查询
//-------------------------响应结果--------------------
// 响应示例
// [
// 'hits' => [
// 'total' => ['value' => 100], // 总匹配数
// 'hits' => [
// [
// '_id' => '123', // 文档ID
// '_source' => [...], // 文档原始数据
// '_score' => 1.2 // 匹配得分(相关性)
// ],
// // ...更多文档
// ]
// ]
// ]
$response = $client->search($params);
// $client->delete([//删除操作
// 'index' => $indexName,
// 'id' => $documentId
// ]);
// 解析结果
echo "匹配到 " . $response['hits']['total']['value'] . " 条数据:\n";
foreach ($response['hits']['hits'] as $hit) {
echo "ID: {$hit['_id']},数据:" . json_encode($hit['_source']) . "\n";
}
}
public function testUpdateBulk(){
// 连接 Elasticsearch
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200']) // 替换为你的 ES 地址
->build();
$indexName = 'users'; // 索引名
// 批量更新的文档信息(每个元素对应一个文档的更新操作)
$documents = [
[
'id' => '1', // 文档 ID
'update_data' => ['age' => 31, 'updated_at' => date('Y-m-d H:i:s')] // 要更新的字段
],
[
'id' => '2',
'update_data' => ['age' => 28, 'hobbies' => ['足球', '音乐']]
]
];
try {
$params = ['body' => []];
// 组装批量更新参数
foreach ($documents as $doc) {
// 每个更新操作需要先添加一个 "update" 指令
$params['body'][] = [
'update' => [
'_index' => $indexName,
'_id' => $doc['id']
]
];
// 接着添加更新的内容(支持 partial update,只更新指定字段)
$params['body'][] = [
'doc' => $doc['update_data'] // doc 表示要更新的字段
// 可选:如果文档不存在,是否创建(默认 false)
// 'doc_as_upsert' => true
];
}
// 执行批量更新
$response = $client->bulk($params);
// 解析结果
if (empty($response['errors'])) {
echo "批量更新成功!\n";
foreach ($response['items'] as $item) {
$id = $item['update']['_id'];
$status = $item['update']['status'];
echo "文档 ID: {$id},状态: {$status}\n";
}
} else {
echo "部分更新失败:\n";
foreach ($response['items'] as $item) {
if (isset($item['update']['error'])) {
$id = $item['update']['_id'];
$error = $item['update']['error']['reason'];
echo "文档 ID: {$id},错误: {$error}\n";
}
}
}
} catch (Exception $e) {
echo "批量更新失败:" . $e->getMessage() . "\n";
}
}
public function testCreateBulk(){
// 连接 Elasticsearch
$client = ClientBuilder::create()
->setHosts(['http://localhost:9200']) // 替换为你的 ES 地址
->build();
$indexName = 'users'; // 目标索引名
// 要批量插入的文档数据(数组形式,每个元素是一条文档)
$documents = [
[
'id' => '1001', // 可选:手动指定文档ID,不指定则ES自动生成
'data' => [
'name' => '张三',
'age' => 28,
'email' => 'zhangsan@example.com',
'created_at' => date('Y-m-d H:i:s')
]
],
[
'id' => '1002',
'data' => [
'name' => '李四',
'age' => 32,
'email' => 'lisi@example.com',
'created_at' => date('Y-m-d H:i:s')
]
],
[
// 不指定ID,由ES自动生成
'data' => [
'name' => '王五',
'age' => 25,
'email' => 'wangwu@example.com',
'created_at' => date('Y-m-d H:i:s')
]
]
];
try {
$params = ['body' => []];
// 组装批量插入参数
foreach ($documents as $doc) {
// 每个插入操作需要先添加一个 "index" 指令
$action = [
'index' => [
'_index' => $indexName
]
];
// 如果指定了ID,添加到指令中
if (isset($doc['id'])) {
$action['index']['_id'] = $doc['id'];
}
// 将指令和文档数据添加到批量请求中
$params['body'][] = $action;
$params['body'][] = $doc['data'];
}
// 执行批量插入
$response = $client->bulk($params);
// 解析结果
if (empty($response['errors'])) {
echo "批量插入成功!共插入 " . count($documents) . " 条文档\n";
foreach ($response['items'] as $item) {
$id = $item['index']['_id'];
$status = $item['index']['status']; // 201 表示创建成功
echo "文档 ID: {$id},状态: {$status}\n";
}
} else {
echo "部分插入失败:\n";
foreach ($response['items'] as $item) {
if (isset($item['index']['error'])) {
$id = $item['index']['_id'] ?? '未知';
$error = $item['index']['error']['reason'];
echo "文档 ID: {$id},错误: {$error}\n";
}
}
}
} catch (Exception $e) {
echo "批量插入失败:" . $e->getMessage() . "\n";
}
}
}