本文目录导读:

为PHP项目对接Elasticsearch实现全文检索,主要有以下几种方案,按推荐程度排序:
官方客户端 elasticsearch-php
安装
composer require elasticsearch/elasticsearch
基础连接配置
use Elastic\Elasticsearch\ClientBuilder;
// 单节点连接
$client = ClientBuilder::create()
->setHosts(['localhost:9200'])
->build();
// 多节点集群连接
$client = ClientBuilder::create()
->setHosts([
'http://node1:9200',
'http://node2:9200',
'http://node3:9200'
])
->setRetries(2) // 重试次数
->build();
// 带认证的连接
$client = ClientBuilder::create()
->setHosts(['https://localhost:9200'])
->setBasicAuthentication('username', 'password')
->setSSLVerification(false) // 开发环境可关闭SSL验证
->build();
索引创建与映射
// 创建索引并定义映射
$params = [
'index' => 'articles',
'body' => [
'settings' => [
'number_of_shards' => 3,
'number_of_replicas' => 1,
'analysis' => [
'analyzer' => [
'ik_smart' => [ // 中文分词
'type' => 'custom',
'tokenizer' => 'ik_smart'
]
]
]
],
'mappings' => [
'properties' => [
'title' => [
'type' => 'text',
'analyzer' => 'ik_max_word',
'search_analyzer' => 'ik_smart'
],
'content' => [
'type' => 'text',
'analyzer' => 'ik_max_word'
],
'author' => [
'type' => 'keyword' // 精确匹配
],
'publish_date' => [
'type' => 'date',
'format' => 'yyyy-MM-dd HH:mm:ss'
],
'views' => [
'type' => 'integer'
],
'tags' => [
'type' => 'keyword'
]
]
]
]
];
$response = $client->indices()->create($params);
数据索引(文档操作)
单条索引
// 索引单条数据
$params = [
'index' => 'articles',
'id' => '1001', // 可选,自动生成id
'body' => [
'title' => 'Elasticsearch PHP集成指南',
'content' => '详细介绍了如何在PHP项目中集成Elasticsearch...',
'author' => '张三',
'publish_date' => '2024-01-15 10:30:00',
'views' => 1256,
'tags' => ['PHP', 'Elasticsearch', '全文检索']
]
];
$response = $client->index($params);
// 批量索引(推荐大数据量使用)
$params = ['body' => []];
$articles = [
['id' => 1, 'title' => '文章1', 'content' => '内容1'],
['id' => 2, 'title' => '文章2', 'content' => '内容2'],
// ... 更多数据
];
foreach ($articles as $article) {
$params['body'][] = [
'index' => [
'_index' => 'articles',
'_id' => $article['id']
]
];
$params['body'][] = [
'title' => $article['title'],
'content' => $article['content']
];
}
$responses = $client->bulk($params);
全文搜索实现
基础搜索
// 全文搜索
$params = [
'index' => 'articles',
'body' => [
'query' => [
'match' => [
'content' => 'Elasticsearch PHP'
]
],
'from' => 0, // 分页
'size' => 10,
'sort' => [
'publish_date' => ['order' => 'desc']
]
]
];
$response = $client->search($params);
$hits = $response['hits']['hits'];
$total = $response['hits']['total']['value'];
foreach ($hits as $hit) {
echo $hit['_source']['title'] . "\n";
echo $hit['_score'] . "\n"; // 相关度分数
}
高级搜索组合
// 组合查询
$params = [
'index' => 'articles',
'body' => [
'query' => [
'bool' => [
'must' => [
'match' => ['title' => 'PHP']
],
'should' => [
'match' => ['content' => 'Elasticsearch']
],
'filter' => [
'range' => [
'publish_date' => [
'gte' => '2024-01-01',
'lte' => '2024-12-31'
]
]
],
'must_not' => [
'term' => ['status' => 'draft']
]
]
],
'highlight' => [
'fields' => [
'title' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>']],
'content' => ['pre_tags' => ['<em>'], 'post_tags' => ['</em>']]
]
]
]
];
$response = $client->search($params);
封装搜索类(推荐)
<?php
namespace App\Services;
use Elastic\Elasticsearch\ClientBuilder;
class ElasticsearchService
{
protected $client;
protected $index;
public function __construct($index = 'articles')
{
$this->client = ClientBuilder::create()
->setHosts(config('elasticsearch.hosts'))
->setBasicAuthentication(
config('elasticsearch.username'),
config('elasticsearch.password')
)
->build();
$this->index = $index;
}
// 索引文档
public function indexDocument(array $document, $id = null)
{
$params = [
'index' => $this->index,
'body' => $document
];
if ($id) {
$params['id'] = $id;
}
return $this->client->index($params);
}
// 搜索
public function search(string $keyword, array $options = [])
{
$params = [
'index' => $this->index,
'body' => [
'query' => [
'multi_match' => [
'query' => $keyword,
'fields' => $options['fields'] ?? ['title^2', 'content'],
'type' => $options['type'] ?? 'best_fields'
]
],
'size' => $options['size'] ?? 10,
'from' => $options['from'] ?? 0,
'highlight' => [
'fields' => [
'title' => new \stdClass(),
'content' => new \stdClass()
]
]
]
];
// 添加排序
if (!empty($options['sort'])) {
$params['body']['sort'] = $options['sort'];
}
// 添加过滤
if (!empty($options['filters'])) {
$params['body']['query']['bool']['filter'] = $options['filters'];
}
return $this->client->search($params);
}
// 删除文档
public function deleteDocument($id)
{
$params = [
'index' => $this->index,
'id' => $id
];
return $this->client->delete($params);
}
// 批量操作
public function bulkIndex(array $documents)
{
$params = ['body' => []];
foreach ($documents as $doc) {
$params['body'][] = [
'index' => [
'_index' => $this->index,
'_id' => $doc['id']
]
];
$params['body'][] = $doc['data'];
}
return $this->client->bulk($params);
}
}
与ORM集成(Laravel例子)
// config/elasticsearch.php
return [
'hosts' => explode(',', env('ELASTICSEARCH_HOSTS', 'localhost:9200')),
'username' => env('ELASTICSEARCH_USERNAME'),
'password' => env('ELASTICSEARCH_PASSWORD'),
];
// 创建Eloquent观察者
namespace App\Observers;
use App\Models\Article;
use App\Services\ElasticsearchService;
class ArticleObserver
{
protected $elasticsearch;
public function __construct(ElasticsearchService $elasticsearch)
{
$this->elasticsearch = $elasticsearch;
}
public function created(Article $article)
{
$this->elasticsearch->indexDocument($article->toArray(), $article->id);
}
public function updated(Article $article)
{
$this->elasticsearch->indexDocument($article->toArray(), $article->id);
}
public function deleted(Article $article)
{
$this->elasticsearch->deleteDocument($article->id);
}
}
数据库同步策略
全量同步
// Artisan命令示例
class SyncArticlesToElasticsearch extends Command
{
public function handle()
{
$elasticsearch = new ElasticsearchService();
Article::chunk(100, function ($articles) use ($elasticsearch) {
$documents = [];
foreach ($articles as $article) {
$documents[] = [
'id' => $article->id,
'data' => $article->toArray()
];
}
$elasticsearch->bulkIndex($documents);
});
$this->info('同步完成');
}
}
增量同步(使用消息队列)
// 队列任务示例
class SyncArticleToES implements ShouldQueue
{
public function handle(ElasticsearchService $elasticsearch)
{
// 处理数据变更
$elasticsearch->indexDocument($this->article->toArray(), $this->article->id);
}
}
性能优化建议
// 1. 连接池配置
$client = ClientBuilder::create()
->setConnectionPool('\Elastic\Elasticsearch\ConnectionPool\StaticConnectionPool')
->setHosts(['localhost:9200'])
->build();
// 2. 批量处理大小
$params['body'] = [];
$batchSize = 500;
foreach ($articles as $index => $article) {
$params['body'][] = ['index' => ['_index' => 'articles', '_id' => $article['id']]];
$params['body'][] = $article;
if (($index + 1) % $batchSize === 0) {
$client->bulk($params);
$params['body'] = [];
}
}
if (!empty($params['body'])) {
$client->bulk($params);
}
// 3. 缓存搜索结果
$cacheKey = 'search_' . md5(json_encode($params));
$results = Cache::remember($cacheKey, 300, function () use ($client, $params) {
return $client->search($params);
});
注意事项
- 中文分词:需要安装IK分词插件
- 索引优化:定期优化索引和清理旧数据
- 错误处理:做好异常捕获和日志记录
- 版本兼容:注意es版本与客户端版本对应
- 安全配置:生产环境开启SSL和认证
通过以上步骤,你可以在PHP项目中完整地对接Elasticsearch实现全文检索功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播