一、为什么选择Elasticsearch做搜索系统

现在很多网站和应用都需要搜索功能,比如电商平台要搜索商品,新闻网站要搜索文章。传统数据库的LIKE查询性能很差,特别是数据量大的时候。Elasticsearch就是专门为解决这个问题而生的。

Elasticsearch是一个基于Lucene的搜索引擎,它最大的特点就是快。它能毫秒级返回搜索结果,即使面对海量数据。而且它支持各种复杂的搜索条件,比如模糊搜索、同义词搜索、地理位置搜索等。

PHP作为最流行的Web开发语言之一,和Elasticsearch配合使用特别合适。PHP有官方提供的Elasticsearch客户端库,用起来很方便。下面我们就来看看具体怎么整合。

二、环境准备和安装

在开始之前,我们需要准备好开发环境。这里我们使用PHP 8.1和Elasticsearch 8.5作为技术栈。

首先安装Elasticsearch,可以去官网下载对应系统的安装包,或者用Docker运行:

docker pull elasticsearch:8.5.0
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:8.5.0

然后安装PHP的Elasticsearch客户端:

composer require elasticsearch/elasticsearch

安装完成后,我们可以测试下连接是否正常:

<?php
require 'vendor/autoload.php';

$client = Elastic\Elasticsearch\ClientBuilder::create()
    ->setHosts(['localhost:9200'])
    ->build();

// 检查连接是否正常
$response = $client->info();
print_r($response->asArray());

如果看到返回了Elasticsearch的版本信息,说明连接成功了。

三、基本操作示例

1. 创建索引

索引相当于数据库中的表。我们先创建一个存储文章数据的索引:

$params = [
    'index' => 'articles',
    'body' => [
        'settings' => [
            'number_of_shards' => 1,
            'number_of_replicas' => 0
        ],
        'mappings' => [
            'properties' => [
                'title' => ['type' => 'text'],
                'content' => ['type' => 'text'],
                'author' => ['type' => 'keyword'],
                'publish_date' => ['type' => 'date'],
                'views' => ['type' => 'integer']
            ]
        ]
    ]
];

$response = $client->indices()->create($params);

这里我们定义了文章的字段类型:

  • title和content是文本类型,会进行分词
  • author是关键字类型,不会分词
  • publish_date是日期类型
  • views是整数类型

2. 添加文档

文档相当于表中的记录。我们来添加几篇文章:

$params = [
    'index' => 'articles',
    'body' => [
        [
            'index' => [
                '_index' => 'articles'
            ]
        ],
        [
            'title' => 'PHP8新特性介绍',
            'content' => 'PHP8带来了JIT编译器、命名参数等新特性...',
            'author' => '张三',
            'publish_date' => '2022-01-01',
            'views' => 1000
        ],
        [
            'index' => [
                '_index' => 'articles'
            ]
        ],
        [
            'title' => 'Elasticsearch入门指南',
            'content' => '本文介绍Elasticsearch的基本概念和使用方法...',
            'author' => '李四',
            'publish_date' => '2022-02-15',
            'views' => 1500
        ]
    ]
];

$response = $client->bulk($params);

这里使用了bulk接口批量添加文档,比单条添加效率高很多。

3. 搜索文档

现在我们来试试搜索功能:

$params = [
    'index' => 'articles',
    'body' => [
        'query' => [
            'match' => [
                'title' => 'PHP'
            ]
        ]
    ]
];

$response = $client->search($params);
print_r($response->asArray());

这个查询会返回标题中包含"PHP"的文章。Elasticsearch的搜索非常灵活,我们还可以组合多个条件:

$params = [
    'index' => 'articles',
    'body' => [
        'query' => [
            'bool' => [
                'must' => [
                    ['match' => ['title' => '指南']],
                    ['range' => ['views' => ['gte' => 1000]]]
                ]
            ]
        ]
    ]
];

这个查询会返回标题包含"指南"并且浏览量大于等于1000的文章。

四、高级搜索功能

1. 高亮显示

搜索结果中高亮显示匹配的关键词:

$params = [
    'index' => 'articles',
    'body' => [
        'query' => [
            'match' => [
                'content' => '特性'
            ]
        ],
        'highlight' => [
            'fields' => [
                'content' => new \stdClass()
            ]
        ]
    ]
];

$response = $client->search($params);
foreach ($response['hits']['hits'] as $hit) {
    echo $hit['highlight']['content'][0] . "\n";
}

2. 聚合统计

Elasticsearch强大的聚合功能可以轻松实现各种统计:

$params = [
    'index' => 'articles',
    'body' => [
        'aggs' => [
            'authors' => [
                'terms' => [
                    'field' => 'author',
                    'size' => 10
                ]
            ],
            'total_views' => [
                'sum' => [
                    'field' => 'views'
                ]
            ]
        ]
    ]
];

$response = $client->search($params);
print_r($response['aggregations']);

这个查询会统计每个作者的文章数量和总浏览量。

3. 拼音搜索

中文搜索经常需要支持拼音,我们可以安装拼音插件:

# 在Elasticsearch中安装拼音插件
bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-pinyin/releases/download/v8.5.0/elasticsearch-analysis-pinyin-8.5.0.zip

然后创建支持拼音的索引:

$params = [
    'index' => 'articles_pinyin',
    'body' => [
        'settings' => [
            'analysis' => [
                'analyzer' => [
                    'pinyin_analyzer' => [
                        'tokenizer' => 'my_pinyin'
                    ]
                ],
                'tokenizer' => [
                    'my_pinyin' => [
                        'type' => 'pinyin',
                        'keep_first_letter' => true,
                        'keep_separate_first_letter' => true,
                        'keep_full_pinyin' => true
                    ]
                ]
            ]
        ],
        'mappings' => [
            'properties' => [
                'title' => [
                    'type' => 'text',
                    'analyzer' => 'pinyin_analyzer'
                ]
            ]
        ]
    ]
];

$client->indices()->create($params);

这样就能用拼音搜索中文了。

五、性能优化建议

  1. 合理设置分片数:分片太多会增加开销,太少会影响性能。一般建议每个分片大小在10-50GB之间。

  2. 使用批量操作:批量添加、更新文档比单条操作效率高很多。

  3. 合理使用索引:只为需要搜索的字段建立索引,避免不必要的索引开销。

  4. 缓存热门查询:可以将热门查询结果缓存在Redis中,减轻Elasticsearch压力。

  5. 定期优化索引:使用_forcemerge接口合并小分段,提高查询性能。

六、应用场景分析

Elasticsearch特别适合以下场景:

  1. 全文搜索:比如新闻、博客、论坛的内容搜索。

  2. 日志分析:集中存储和分析大量日志数据。

  3. 电商搜索:支持商品的多维度筛选和搜索。

  4. 地理位置搜索:查找附近的商家或服务。

  5. 数据分析:利用聚合功能进行数据统计和分析。

七、技术优缺点

优点:

  • 查询速度极快,毫秒级响应
  • 支持复杂的搜索条件
  • 水平扩展能力强
  • 丰富的聚合分析功能
  • 社区活跃,文档完善

缺点:

  • 不适合频繁更新的场景
  • 资源消耗较大
  • 学习曲线较陡
  • 数据一致性不如传统数据库

八、注意事项

  1. 数据安全:Elasticsearch默认没有密码验证,生产环境一定要配置安全选项。

  2. 数据备份:定期备份索引数据,防止数据丢失。

  3. 版本兼容:PHP客户端版本要和Elasticsearch版本匹配。

  4. 中文分词:默认分词器对中文支持不好,建议安装ik等中文分词插件。

  5. 监控维护:使用Kibana等工具监控集群状态,及时发现并解决问题。

九、总结

PHP和Elasticsearch的整合能构建出强大的搜索系统。通过本文的介绍,你应该已经掌握了从环境搭建到高级搜索的全套流程。实际项目中,可以根据需求选择合适的搜索策略和优化方案。

Elasticsearch虽然功能强大,但也不是万能的。对于简单的搜索需求,可能数据库自带的搜索功能就足够了。但对于复杂的搜索场景,Elasticsearch绝对是值得投入学习的技术。