先直接贴 GitHub repo: RunnerLee/esq-builder
自己在实际项目里面比较少用到 es,没什么深度使用的场景。根据几个遇到的基础使用场景总结,想要解决几个问题:
在此之前,想要做一个简单的列表搜索,例如 “商品末级分类+商品名称前缀+创建者/维护者”,在 php 中需要拼装这样非常不直观的数组:
$query = [
'bool' => [
'must' => [
[
'term' => [
'category_id' => 1,
],
],
[
'prefix' => [
'goods_name' => 'abc',
],
],
[
'bool' => [
'should' => [
[
'term' => [
'create_uid' => 'runnerlee',
],
],
[
'term' => [
'update_uid' => 'runnerlee',
],
]
],
],
]
],
],
];
在 GitHub 搜轮子搜到这个:https://github.com/ongr-io/ElasticsearchDSL
他的用法是这样的:
$matchAll = new ONGR\ElasticsearchDSL\Query\MatchAllQuery();
$search = new ONGR\ElasticsearchDSL\Search();
$search->addQuery($matchAll);
$params = [
'index' => 'your_index',
'body' => $search->toArray(),
];
$results = $client->search($params);
结合平常用的 laravel 的 eloquent,我想要能否这样去拼装我的查询:
$query = new QueryBuilder();
$query
->term('demo_field', 'demo_value')
->prefix('demo_field_2', 'demo_value_2');
// 一开始想过用这种形势
// $query->where('term', 'demo_field', 'demo_value');
// 或者是这种
// $query->whereTerm('demo_field', 'demo_value');
// 但觉得这样在阅读代码理解查询逻辑时不太友善
借用 ongr/elasticsearch-dsl 套一层封装,现在对最上面的例子可以这么处理了:
use Runner\EsqBuilder\QueryBuilder;
use Runner\EsqBuilder\SearchBuilder;
$builder = new SearchBuilder();
$builder->query()
->term('category_id', 1)
->prefix('goods_name', 'abc')
->bool(function (QueryBuilder $query) {
$query->shouldTerm('create_uid', 'runnerlee')
->shouldTerm('update_uid', 'runnerlee');
});
感觉还是清爽的。在 QueryBuilder 中,把 query 当作是一个大的 bool, 你可以直接调用支持的 clause 来往 bool 里加查询条件,默认的类型为 must.
你也可以用 <boolType><clause> 来指定 clause 的类型。例如 $query->shouldTerm() 或是 $query->mustNotTerm().
嵌套 bool 的使用就跟 eloquent 的 Model::query() 方法类似了。
整个 SearchBuilder 由四个 components 组成:
给上面的例子加上排序和分页:
$page = min(100, max(1, $_GET['page'] ?? 1));
$perPage = 20;
$builder->setFrom(($page - 1) * $perPage);
$builder->setSize($perPage);
$builder->sort()->fieldSort('id', 'desc');
$response = $builder
->setClient(ClientBuilder::create()->build())
->serach('your_index');