ensi / laravel-elastic-query-specification
laravel elastic 查询规范
Requires
- php: ^8.1
- ensi/laravel-elastic-query: ^8.1.0
- laravel/framework: ^9.0 || ^10.0 || ^11.0
- webmozart/assert: ^1.11
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.2
- orchestra/testbench: ^7.0 || ^8.0 || ^9.0
- pestphp/pest: ^1.22 || ^2.0
- pestphp/pest-plugin-laravel: ^1.1 || ^2.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan: ^1.11
- spaze/phpstan-disallowed-calls: ^2.15
README
用于描述查询的声明式方法的 ensi/laravel-elastic-query 扩展。
安装
- 安装 ensi/laravel-elastic-query https://github.com/ensi-platform/laravel-elastic-query#installation
- 通过 composer 安装此包
composer require ensi/laravel-elastic-query-specification
版本兼容性
基本用法
所有声明式查询类型均基于规范。它包含可用过滤器、排序和聚合的定义。
use Ensi\LaravelElasticQuerySpecification\Agregating\AllowedAggregate; use Ensi\LaravelElasticQuerySpecification\Filtering\AllowedFilter; use Ensi\LaravelElasticQuerySpecification\Sorting\AllowedSort; use Ensi\LaravelElasticQuerySpecification\Specification\CompositeSpecification; use Ensi\LaravelElasticQuerySpecification\Specification\Specification; class ProductSpecification extends CompositeSpecification { public function __construct() { parent::__construct(); $this->allowedFilters([ 'package', 'active', AllowedFilter::exact('cashback', 'cashback.active')->default(true) ]); $this->allowedSorts(['name', 'rating']); $this->allowedAggregates([ 'package', AllowedAggregate::minmax('rating') ]); $this->allowedFacets([ 'package' ]); $this->whereNotNull('package'); $this->nested('offers', function (Specification $spec) { $spec->allowedFilters(['seller_id', 'active']); $spec->allowedAggregates([ 'seller_id', AllowedAggregate::minmax('price') ]); $spec->allowedSorts([ AllowedSort::field('price')->byMin() ]); $spec->allowedFacets([ AllowedFacet::terms('seller_id') ]); }); } }
以下是该规范的查询示例。
{ "sort": ["+price", "-rating"], "filter": { "active": true, "seller_id": 10 } }
{ "aggregate": ["price", "rating"], "filter": { "package": "bottle", "seller_id": 10 } }
{ "facet": ["seller_id", "package"], "filter": { "package": "bottle", "seller_id": [10, 20, 50, 90] } }
使用 nested
方法为嵌套文档添加规范。过滤器、聚合和排序的名称从它们导出到全局作用域,不添加任何前缀。对于过滤器可以使用相同的名称,但不能用于其他组件。
$this->nested('nested_field', function (Specification $spec) { ... }) $this->nested('nested_field', new SomeSpecificationImpl());
在嵌套文档的规范中,只能使用这些文档的字段。
对于相同的 nested
字段添加多个规范是可接受的。
where*
约束允许您设置客户端无法更改的额外程序选择条件。根规范中指定的约束始终应用。嵌套规范中的约束仅用作查询中添加的过滤器、聚合或排序的附加。
allowedFilters
方法确定客户端可用的过滤器。每个过滤器必须在规范中具有唯一名称。同时,在根和嵌套规范或不同的嵌套规范中,名称可能重复。所有具有相同名称的过滤器将使用查询参数中的一个值进行填充。
除了过滤器本身的名称外,您还可以单独指定应用于索引中字段的名称和默认值。
$this->allowedFilters([AllowedFilter::exact('name', 'field')->default(500)]); // the following statements are equivalent $this->allowedFilters(['name']); $this->allowedFilters([AllowedFilter::exact('name', 'name')]);
过滤器类型
AllowedFilter::exact('name', 'field'); // The field value is checked for equality to one of the specified AllowedFilter::exists('name', 'field'); // There is a check that the field is in the document and has a non-zero value. AllowedFilter::greater('name', 'field'); // The field value must be greater than the specified one. AllowedFilter::greaterOrEqual('name', 'field'); // The field value must be greater than or equal to the specified one. AllowedFilter::less('name', 'field'); // The field value must be less than the specified one. AllowedFilter::lessOrEqual('name', 'field'); // The field value must be less than or equal to the specified one. AllowedFilter::match('name', 'field'); // Full text search in the field AllowedFilter::multiMatch('name', ['field1^3', 'field2']); // Full text search in the fields
客户端可用的排序是通过 allowedSorts
方法添加的。排序方向由其名称设置。符号 +
或无符号对应于升序,-
对应于降序。默认情况下,使用最小选择进行升序排序,如果字段中有多个值。
$this->allowedSorts([AllowedSort::field('name', 'field')]); // the following statements are equivalent $this->allowedSorts(['name']); $this->allowedSorts([AllowedSort::field('+name', 'name')]); $this->allowedSorts([AllowedSort::field('+name', 'name')->byMin()]); // set the sorting mode $this->allowedSorts([AllowedSort::field('name', 'field')->byMin()]); $this->allowedSorts([AllowedSort::field('name', 'field')->byMax()]); $this->allowedSorts([AllowedSort::field('name', 'field')->byAvg()]); $this->allowedSorts([AllowedSort::field('name', 'field')->bySum()]); $this->allowedSorts([AllowedSort::field('name', 'field')->byMedian()]);
从嵌套规范进行排序时,将考虑同一规范中的所有约束和活动过滤器。
使用 allowedAggregates
方法声明聚合。客户端在查询参数中指定预期在响应中接收的聚合名称列表。
$this->allowedAggregates([AllowedAggregate::terms('name', 'field')]); // the following statements are equivalent $this->allowedAggregates(['name']); $this->allowedAggregates([AllowedAggregate::terms('name', 'name')]);
聚合类型
AllowedAggregate::terms('name', 'field'); // Get all variants of attribute values AllowedAggregate::minmax('name', 'field'); // Get min and max attribute values
嵌套规范中的聚合将带有所有约束和活动过滤器添加到 Elasticsearch 查询中。
您可以使用 allowedFacets
方法定义分面。每个分面需要一个聚合和一个或多个过滤器。您可以使用现有的聚合
AllowedFacet::fromAggregate('name', 'filter');
和由分面本身创建的聚合
AllowedFacet::terms('name', 'filter'); AllowedFacet::minmax('name', ['filter1', 'filter2']);
单独在规范中注册过滤器。只有它们的名称传递给分面创建方法。
在计算每个分面可用的值时,除了与该分面关联的过滤器外,所有设置的过滤器都将应用。
搜索文档
use Ensi\LaravelElasticQuerySpecification\SearchQueryBuilder; use Ensi\LaravelElasticQuerySpecification\QueryBuilderRequest; class ProductsSearchQuery extends SearchQueryBuilder { public function __construct(QueryBuilderRequest $request) { parent::__construct(ProductsIndex::query(), new ProductSpecification(), $request); } }
class ProductsController { // ... public function index(ProductsSearchQuery $query) { return ProductResource::collection($query->get()); } }
计算汇总指标
use Ensi\LaravelElasticQuerySpecification\AggregateQueryBuilder; use Ensi\LaravelElasticQuerySpecification\QueryBuilderRequest; class ProductsAggregateQuery extends AggregateQueryBuilder { public function __construct(QueryBuilderRequest $request) { parent::__construct(ProductsIndex::aggregate(), new ProductSpecification(), $request); } }
class ProductsController { // ... public function totals(ProductsAggregateQuery $query) { return new ProductAggregateResource($query->get()); } }
确定可用的分面值
use Ensi\LaravelElasticQuerySpecification\FacetQueryBuilder; use Ensi\LaravelElasticQuerySpecification\QueryBuilderRequest; class ProductsFacetsQuery extends FacetQueryBuilder { public function __construct(QueryBuilderRequest $request) { parent::__construct(ProductsIndex::aggregate(), new ProductSpecification(), $request); } }
class ProductsController { // ... public function facets(ProductsFacetsQuery $query) { return new ProductFacetsResource($query->get()); } }
Elasticsearch 7 和 8 支持。
由于 Elasticsearch 7 和 8 的客户端不兼容,将为这些版本创建单独的发布版本。每个版本的开发都在相应的分支上进行。
要修改 7 版本,您需要基于 v7 创建一个任务分支,并向它提交一个 pull request。对于 8 版本,类似,但基于 v8 分支。
贡献
有关详细信息,请参阅 CONTRIBUTING。
测试
- composer install
- 以您喜欢的方式启动 Elasticsearch
- 如果您需要更改
ELASTICSEARCH_HOSTS
,请将phpunit.xml.dist
复制到phpunit.xml
并填写值 - composer test
安全漏洞
请查看我们如何报告安全漏洞的 安全策略。
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。