ykan / elastx
Elasticsearch DSL query builder for PHP
v7.0.0-beta.1
2026-05-26 16:30 UTC
Requires
- php: >=7.2
- elasticsearch/elasticsearch: ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.9
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.1
- phpunit/phpunit: >=8.0
This package is auto-updated.
Last update: 2026-05-28 02:35:03 UTC
README
A PHP library for building Elasticsearch DSL queries and managing indices. Targets ES 7.x.
Covers all query types (compound, full-text, term-level, geo, joining, span, shape, specialized), all 47 aggregation types, and 26 search request parameters.
Requirements
- PHP 7.2+
- Elasticsearch 7.x
Installation
composer require ykan/elastx:^7
Quick Start
use ykan\DSL\Query; use ykan\DSL\Type\FullText\Match_; $query = new Query(); $query->bool([ 'must' => function (Query $q) { $q->match('title', function (Match_ $m) { $m->query('elasticsearch')->fuzziness('AUTO'); }); }, 'filter' => function (Query $q) { $q->range('price', [10, 100]); $q->term('status', 'published'); }, 'should' => function (Query $q) { $q->match('category', 'database'); }, ]); $query->aggs('price_stats')->stats(['field' => 'price']); $query->aggs('by_category')->terms(['field' => 'category', 'size' => 10]); echo $query->toJson();
Output:
{
"query": {
"bool": {
"must": [{ "match": { "title": { "query": "elasticsearch", "fuzziness": "AUTO" } } }],
"filter": [{ "range": { "price": { "gte": 10, "lte": 100 } } }, { "term": { "status": "published" } }],
"should": [{ "match": { "category": "database" } }]
}
},
"aggs": {
"price_stats": { "stats": { "field": "price" } },
"by_category": { "terms": { "field": "category", "size": 10 } }
}
}
Retrieve aggregation results after search:
$results->aggregations(); // ['price_stats' => [...], 'by_category' => [...]]
Index Layer
use ykan\Index\Index; class ProductIndex extends Index { protected $name = 'products'; protected $mappings = [ 'properties' => [ 'title' => ['type' => 'text'], 'price' => ['type' => 'float'], 'status' => ['type' => 'keyword'], ], ]; }
Register the ES client during bootstrap:
Index::setClient($client);
Search
use ykan\DSL\Query; $results = ProductIndex::newQuery() ->bool('must', function (Query $q) { $q->match('title', 'elasticsearch'); }) ->sort('price', 'asc') ->size(20) ->get(); $results->total(); // int $results->docs(); // array of _source $results->ids(); // array of _id $results->aggregations(); // aggregation results
For large result sets, use cursor() to iterate all matching documents via scroll:
$search = ProductIndex::newQuery()->match('title', 'test'); foreach ($search->cursor() as $doc) { // process $doc }
Document CRUD
$doc = ProductIndex::newDoc(1); $doc->create(['title' => 'New Product', 'price' => 29.99]); $doc->index(['title' => 'Updated', 'price' => 39.99]); // create or overwrite $doc->source(); // _source array $doc->get(); // full document with _id, _version, etc. $doc->exists(); // bool $doc->update(['price' => 39.99]); $doc->delete(); $doc->retryOnConflict(3)->update(['price' => 39.99]);
Bulk
use ykan\Index\Bulk; $bulk = new Bulk(new ProductIndex()); $bulk->index(1, ['title' => 'Product A']); $bulk->index(2, ['title' => 'Product B']); $bulk->delete(3); $bulk->execute();
Index Management
use ykan\Index\Manager; $manager = new Manager(new ProductIndex()); $manager->create(); $manager->exists(); // true $manager->delete(); $manager->putMapping($mapping); $manager->addAlias('products_alias'); $manager->removeAlias('products_alias'); $manager->swapAlias('products_alias', 'old_index');
Rebuild
Zero-downtime rebuild: create new index, import data, swap alias.
use ykan\Index\Rebuild; $rebuild = new Rebuild(new ProductIndex()); // Run with Index::source() $rebuild->batchSize(500)->run(); // Rollback to previous index $rebuild->rollback(); $rebuild->rollback('products_20260525_120000'); // or specify target // Clean orphan indexes $rebuild->orphans(); // ['products_20260527_100000', ...] $rebuild->cleanOrphans();
Provide data by overriding source(), or pass a custom source to run():
// Override in Index subclass class ProductIndex extends Index { public function source(array $options = []): iterable { foreach (Product::all() as $product) { yield $product->id => $product->toArray(); } } } // Or pass at call time $rebuild->source($rows)->run();
License
MIT