1. 使用 Composer 安装
# 安装 Composer(如果未安装)
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
# 创建项目目录
mkdir elasticsearch-php-demo
cd elasticsearch-php-demo
# 初始化 Composer
composer init
# 安装 Elasticsearch PHP 客户端
composer require elasticsearch/elasticsearch
2. 手动安装(不使用 Composer)
<?php
// 手动引入 Elasticsearch 客户端
require_once 'path/to/elasticsearch-php/autoload.php';
示例 1:基础连接和索引操作
<?php
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;
class ElasticsearchDemo {
private $client;
public function __construct() {
// 创建 Elasticsearch 客户端
$this->client = ClientBuilder::create()
->setHosts(['localhost:9200']) // ES 服务器地址
->setRetries(2) // 重试次数
->build();
// 检查连接
if (!$this->checkConnection()) {
throw new Exception("无法连接到 Elasticsearch");
}
}
/**
* 检查 Elasticsearch 连接
*/
private function checkConnection() {
try {
return $this->client->ping();
} catch (Exception $e) {
echo "连接失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 创建索引
*/
public function createIndex($indexName) {
$params = [
'index' => $indexName,
'body' => [
'settings' => [
'number_of_shards' => 2,
'number_of_replicas' => 1
],
'mappings' => [
'properties' => [
'title' => [
'type' => 'text',
'analyzer' => 'standard'
],
'content' => [
'type' => 'text',
'analyzer' => 'standard'
],
'author' => [
'type' => 'keyword'
],
'publish_date' => [
'type' => 'date'
],
'views' => [
'type' => 'integer'
]
]
]
]
];
try {
$response = $this->client->indices()->create($params);
echo "索引 {$indexName} 创建成功\n";
return $response;
} catch (Exception $e) {
echo "创建索引失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 删除索引
*/
public function deleteIndex($indexName) {
$params = ['index' => $indexName];
try {
// 检查索引是否存在
if ($this->client->indices()->exists($params)) {
$response = $this->client->indices()->delete($params);
echo "索引 {$indexName} 删除成功\n";
return $response;
} else {
echo "索引 {$indexName} 不存在\n";
return false;
}
} catch (Exception $e) {
echo "删除索引失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 添加文档
*/
public function addDocument($indexName, $document, $id = null) {
$params = [
'index' => $indexName,
'body' => $document
];
// 如果指定了 ID
if ($id !== null) {
$params['id'] = $id;
}
try {
$response = $this->client->index($params);
echo "文档添加成功,ID: " . $response['_id'] . "\n";
return $response;
} catch (Exception $e) {
echo "添加文档失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 获取文档
*/
public function getDocument($indexName, $id) {
$params = [
'index' => $indexName,
'id' => $id
];
try {
$response = $this->client->get($params);
return $response;
} catch (Exception $e) {
echo "获取文档失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 更新文档
*/
public function updateDocument($indexName, $id, $updateData) {
$params = [
'index' => $indexName,
'id' => $id,
'body' => [
'doc' => $updateData
]
];
try {
$response = $this->client->update($params);
echo "文档更新成功\n";
return $response;
} catch (Exception $e) {
echo "更新文档失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 删除文档
*/
public function deleteDocument($indexName, $id) {
$params = [
'index' => $indexName,
'id' => $id
];
try {
$response = $this->client->delete($params);
echo "文档删除成功\n";
return $response;
} catch (Exception $e) {
echo "删除文档失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 搜索文档
*/
public function search($indexName, $query) {
$params = [
'index' => $indexName,
'body' => [
'query' => $query
]
];
try {
$response = $this->client->search($params);
return $response;
} catch (Exception $e) {
echo "搜索失败: " . $e->getMessage() . "\n";
return false;
}
}
/**
* 批量插入文档
*/
public function bulkInsert($indexName, $documents) {
$params = ['body' => []];
foreach ($documents as $document) {
$params['body'][] = [
'index' => [
'_index' => $indexName
]
];
$params['body'][] = $document;
}
try {
$response = $this->client->bulk($params);
echo "批量插入完成,处理了 " . count($documents) . " 个文档\n";
return $response;
} catch (Exception $e) {
echo "批量插入失败: " . $e->getMessage() . "\n";
return false;
}
}
}
// 使用示例
try {
$es = new ElasticsearchDemo();
// 创建索引
$es->createIndex('blog');
// 添加单个文档
$document = [
'title' => 'Elasticsearch PHP 客户端使用指南',
'content' => '这是一篇关于如何使用 PHP 操作 Elasticsearch 的详细教程。',
'author' => '张三',
'publish_date' => '2023-10-01',
'views' => 100
];
$es->addDocument('blog', $document, '1');
// 批量插入文档
$documents = [
[
'title' => 'PHP 开发技巧',
'content' => '分享一些 PHP 开发中的实用技巧和最佳实践。',
'author' => '李四',
'publish_date' => '2023-10-02',
'views' => 150
],
[
'title' => 'Linux 系统管理',
'content' => 'Linux 系统管理的基本命令和操作指南。',
'author' => '王五',
'publish_date' => '2023-10-03',
'views' => 200
]
];
$es->bulkInsert('blog', $documents);
// 搜索文档
$query = [
'match' => [
'title' => 'PHP'
]
];
$searchResult = $es->search('blog', $query);
echo "搜索到 " . $searchResult['hits']['total']['value'] . " 个结果:\n";
foreach ($searchResult['hits']['hits'] as $hit) {
echo "- " . $hit['_source']['title'] . " (作者: " . $hit['_source']['author'] . ")\n";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "\n";
}
?>
示例 2:高级搜索功能
<?php
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;
class AdvancedSearchDemo {
private $client;
public function __construct() {
$this->client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
}
/**
* 多字段搜索
*/
public function multiFieldSearch($indexName, $keyword) {
$params = [
'index' => $indexName,
'body' => [
'query' => [
'multi_match' => [
'query' => $keyword,
'fields' => ['title^2', 'content', 'author'], // title 字段权重为 2
'type' => 'best_fields'
]
],
'highlight' => [
'fields' => [
'title' => new \stdClass(),
'content' => new \stdClass()
]
]
]
];
return $this->client->search($params);
}
/**
* 布尔搜索
*/
public function boolSearch($indexName, $must = [], $should = [], $must_not = []) {
$boolQuery = [];
if (!empty($must)) {
$boolQuery['must'] = $must;
}
if (!empty($should)) {
$boolQuery['should'] = $should;
}
if (!empty($must_not)) {
$boolQuery['must_not'] = $must_not;
}
$params = [
'index' => $indexName,
'body' => [
'query' => [
'bool' => $boolQuery
]
]
];
return $this->client->search($params);
}
/**
* 范围查询
*/
public function rangeSearch($indexName, $field, $gte = null, $lte = null) {
$range = [];
if ($gte !== null) $range['gte'] = $gte;
if ($lte !== null) $range['lte'] = $lte;
$params = [
'index' => $indexName,
'body' => [
'query' => [
'range' => [
$field => $range
]
]
]
];
return $this->client->search($params);
}
/**
* 聚合查询
*/
public function aggregationSearch($indexName) {
$params = [
'index' => $indexName,
'body' => [
'size' => 0, // 不需要返回具体文档
'aggs' => [
'authors' => [
'terms' => [
'field' => 'author.keyword',
'size' => 10
]
],
'total_views' => [
'sum' => [
'field' => 'views'
]
],
'avg_views' => [
'avg' => [
'field' => 'views'
]
]
]
]
];
return $this->client->search($params);
}
}
// 使用示例
$searchDemo = new AdvancedSearchDemo();
// 多字段搜索
$result = $searchDemo->multiFieldSearch('blog', 'PHP');
print_r($result['hits']);
// 布尔搜索
$boolResult = $searchDemo->boolSearch('blog',
[ // must 条件
['match' => ['author' => '张三']],
['range' => ['views' => ['gte' => 50]]]
],
[ // should 条件
['match' => ['title' => '教程']],
['match' => ['content' => '指南']]
]
);
// 聚合查询
$aggResult = $searchDemo->aggregationSearch('blog');
echo "总浏览量: " . $aggResult['aggregations']['total_views']['value'] . "\n";
echo "平均浏览量: " . $aggResult['aggregations']['avg_views']['value'] . "\n";
?>
示例 3:完整的博客搜索应用
<?php
require 'vendor/autoload.php';
use Elasticsearch\ClientBuilder;
class BlogSearch {
private $client;
private $indexName = 'blog_posts';
public function __construct() {
$this->client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
$this->createBlogIndex();
}
private function createBlogIndex() {
// 检查索引是否存在,不存在则创建
if (!$this->client->indices()->exists(['index' => $this->indexName])) {
$params = [
'index' => $this->indexName,
'body' => [
'settings' => [
'number_of_shards' => 1,
'number_of_replicas' => 1,
'analysis' => [
'analyzer' => [
'ik_smart_analyzer' => [
'type' => 'custom',
'tokenizer' => 'ik_smart'
]
]
]
],
'mappings' => [
'properties' => [
'title' => [
'type' => 'text',
'analyzer' => 'ik_smart_analyzer'
],
'content' => [
'type' => 'text',
'analyzer' => 'ik_smart_analyzer'
],
'author' => [
'type' => 'keyword'
],
'tags' => [
'type' => 'keyword'
],
'category' => [
'type' => 'keyword'
],
'publish_date' => [
'type' => 'date'
],
'views' => [
'type' => 'integer'
],
'status' => [
'type' => 'keyword'
]
]
]
]
];
$this->client->indices()->create($params);
}
}
public function addBlogPost($post) {
$params = [
'index' => $this->indexName,
'body' => $post
];
return $this->client->index($params);
}
public function searchPosts($keyword, $filters = [], $page = 1, $pageSize = 10) {
$from = ($page - 1) * $pageSize;
$query = [
'bool' => [
'must' => [],
'filter' => []
]
];
// 关键词搜索
if (!empty($keyword)) {
$query['bool']['must'][] = [
'multi_match' => [
'query' => $keyword,
'fields' => ['title^3', 'content^2', 'tags^2'],
'type' => 'best_fields'
]
];
}
// 过滤器
foreach ($filters as $field => $value) {
if (!empty($value)) {
$query['bool']['filter'][] = [
'term' => [$field => $value]
];
}
}
$params = [
'index' => $this->indexName,
'body' => [
'from' => $from,
'size' => $pageSize,
'query' => $query,
'sort' => [
['publish_date' => ['order' => 'desc']],
['views' => ['order' => 'desc']]
],
'highlight' => [
'fields' => [
'title' => [
'number_of_fragments' => 0
],
'content' => [
'fragment_size' => 150,
'number_of_fragments' => 3
]
]
]
]
];
$response = $this->client->search($params);
return [
'total' => $response['hits']['total']['value'],
'posts' => $response['hits']['hits'],
'took' => $response['took']
];
}
public function getRelatedPosts($postId, $limit = 5) {
// 先获取当前文章
$currentPost = $this->client->get([
'index' => $this->indexName,
'id' => $postId
]);
$tags = $currentPost['_source']['tags'] ?? [];
if (empty($tags)) {
return [];
}
$params = [
'index' => $this->indexName,
'body' => [
'size' => $limit,
'query' => [
'bool' => [
'must' => [
'terms' => [
'tags' => $tags
]
],
'must_not' => [
'term' => [
'_id' => $postId
]
]
]
],
'sort' => [
['views' => ['order' => 'desc']],
['publish_date' => ['order' => 'desc']]
]
]
];
$response = $this->client->search($params);
return $response['hits']['hits'];
}
}
// 使用示例
$blogSearch = new BlogSearch();
// 添加示例文章
$samplePosts = [
[
'title' => 'PHP 8 新特性详解',
'content' => 'PHP 8 引入了许多令人兴奋的新特性,如命名参数、联合类型、属性等...',
'author' => '技术达人',
'tags' => ['PHP', '编程', '后端'],
'category' => '编程语言',
'publish_date' => '2023-09-15',
'views' => 245,
'status' => 'published'
],
[
'title' => 'Elasticsearch 入门教程',
'content' => '学习如何使用 Elasticsearch 进行全文搜索和数据聚合...',
'author' => '搜索专家',
'tags' => ['Elasticsearch', '搜索', '数据库'],
'category' => '数据库',
'publish_date' => '2023-09-20',
'views' => 189,
'status' => 'published'
]
];
foreach ($samplePosts as $post) {
$blogSearch->addBlogPost($post);
}
// 搜索文章
$result = $blogSearch->searchPosts('PHP 教程', ['category' => '编程语言'], 1, 10);
echo "找到 {$result['total']} 篇文章,耗时 {$result['took']} 毫秒\n";
foreach ($result['posts'] as $post) {
echo "标题: " . $post['_source']['title'] . "\n";
if (isset($post['highlight'])) {
echo "高亮: " . implode('...', $post['highlight']['content'] ?? []) . "\n";
}
echo "---\n";
}
?>
评论 (0)