-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4361bd7
Showing
20 changed files
with
1,146 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# EditorConfig is awesome: http://EditorConfig.org | ||
|
||
# top-most EditorConfig file | ||
root = true | ||
|
||
# Unix-style newlines with a newline ending every file | ||
[*] | ||
end_of_line = lf | ||
insert_final_newline = true | ||
charset = utf-8 | ||
indent_style = space | ||
indent_size = 4 | ||
|
||
# Tab indentation (no size specified) | ||
[Makefile] | ||
indent_style = tab |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
vendor/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
test: ## Run test suite | ||
./vendor/bin/phpunit --bootstrap vendor/autoload.php --testdox --colors=always tests | ||
|
||
start: ## Start testing tools (Elasticsearch) | ||
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0 | ||
|
||
kibana: ## Start debug tools | ||
docker run -e "ELASTICSEARCH_HOSTS=http://127.0.0.1:9200/" --network host docker.elastic.co/kibana/kibana-oss:7.0.0 | ||
|
||
cs: ## Fix PHP CS | ||
./vendor/bin/php-cs-fixer fix --verbose --rules=@Symfony,ordered_imports src/ | ||
./vendor/bin/php-cs-fixer fix --verbose --rules=@Symfony,ordered_imports tests/ | ||
|
||
.PHONY: help | ||
|
||
help: ## Display this help | ||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | ||
|
||
.DEFAULT_GOAL := help |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# Elastically, **Elastica** based framework | ||
|
||
*This project is a work in progress.* | ||
|
||
 | ||
|
||
**Feedback welcome!** | ||
|
||
Opinionated [Elastica](https://github.com/ruflin/Elastica) based framework to bootstrap PHP and Elasticsearch implementations. | ||
|
||
- DTO are first class citizen, you send object for documents, and get objects back, **like an ODM**; | ||
- All indexes are versioned / aliased; | ||
- Mappings are done in YAML; | ||
- Analysis is separated from mappings; | ||
- 100% compatibility with [ruflin/elastica](https://github.com/ruflin/Elastica); | ||
- Designed for Elasticsearch 7+ (no types); | ||
- Extra commands to monitor, update mapping, reindex... Commonly implemented tasks. | ||
|
||
## Demo | ||
|
||
Quick example of what the library do on top of Elastica: | ||
|
||
```php | ||
<?php | ||
|
||
// Your own DTO, or one generated by Jane (see below) | ||
class AwesomeDTO | ||
{ | ||
public $foo; | ||
public $bar; | ||
} | ||
|
||
// Building the Index from a mapping config | ||
use JoliCode\Elastically\Client; | ||
use Elastica\Document; | ||
|
||
// New Client object with new options | ||
new Client([ | ||
// Where to find the mappings | ||
Client::CONFIG_MAPPINGS_DIRECTORY => './configs', | ||
// What object to find in each index | ||
Client::CONFIG_INDEX_CLASS_MAPPING => [ | ||
'beers' => AwesomeDTO::class, | ||
], | ||
]); | ||
|
||
// Service to build Indexes | ||
$indexBuilder = $client->getIndexBuilder(); | ||
|
||
// Create the Index in Elasticsearch | ||
$index = $indexBuilder->createIndex('beers'); | ||
|
||
// Set the proper aliases | ||
$indexBuilder->markAsLive($index, 'beers'); | ||
|
||
// Service to index DTO in an Index | ||
$indexer = $client->getIndexer(); | ||
|
||
$dto = new AwesomeDTO(); | ||
$dto->bar = 'American Pale Ale'; | ||
$dto->foo = 'Hops from Alsace, France'; | ||
|
||
// Add a document to the queue | ||
$indexer->scheduleIndex('beers', new Document('123', $dto)); | ||
$indexer->flush(); | ||
|
||
// Force index refresh if needed | ||
$indexer->refresh('beers'); | ||
|
||
// Get the Document (new!) | ||
$results = $client->getIndex('beers')->getDocument('123'); | ||
|
||
// Get the DTO (new!) | ||
$results = $client->getIndex('beers')->getModel('123'); | ||
|
||
// Perform a search | ||
$results = $client->getIndex('beers')->search('alsace'); | ||
|
||
// Get the Elastic Document | ||
$results->getDocuments()[0]; | ||
|
||
// Get the Elastica compatible Result | ||
$results->getResults()[0]; | ||
|
||
// Get the DTO 🎉 (new!) | ||
$results->getResults()[0]->getModel(); | ||
``` | ||
|
||
*configs/beers.yaml* | ||
|
||
```yaml | ||
# Anything you want, no validation | ||
mappings: | ||
properties: | ||
foo: | ||
type: text | ||
analyzer: english | ||
fields: | ||
keyword: | ||
type: keyword | ||
``` | ||
## Configuration | ||
This library add custom configurations on top of Elastica's: | ||
### Client::CONFIG_MAPPINGS_DIRECTORY | ||
The directory Elastically is going to look for YAML. | ||
When creating a `foobar` index, a `foobar.yaml` file is expected. | ||
|
||
If an `analyzers.yaml` file is present, **all** the indices will get it. | ||
|
||
### Client::CONFIG_INDEX_CLASS_MAPPING | ||
|
||
An array of index name to class FQN. | ||
|
||
```php | ||
[ | ||
'indexName' => '\My\AwesomeDTO' | ||
] | ||
``` | ||
|
||
### Client::CONFIG_SERIALIZER (optional) | ||
|
||
A `SerializerInterface` and `DenormalizerInterface` compatible object that will by used both on indexation and search. | ||
|
||
Default to Symfony Object Normalizer which can be slow. See below for Jane usage. | ||
|
||
*Todo: add custom demo?* | ||
|
||
### Client::CONFIG_BULK_SIZE (optional) | ||
|
||
When running indexation of lots of documents, this setting allow you to fine-tune the number of document threshold. Default to 100. | ||
|
||
## Using Jane for DTO and fast Normalizers | ||
|
||
To write. | ||
|
||
## To be done | ||
|
||
- some "todo" in the code | ||
- optional Doctrine connector | ||
- check Symfony 3.4 compatibility | ||
- optional Symfony integration (DIC) | ||
- scripts / commands for common tasks: | ||
- auto-reindex when the mapping change, handle the aliases and everything | ||
- micro monitoring for cluster / indexes | ||
- health-check method | ||
|
||
## Sponsors | ||
|
||
[](https://jolicode.com) | ||
|
||
Open Source time sponsored by JoliCode. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "jolicode/elastically", | ||
"description": "Opinionated Elastica based framework to bootstrap PHP and Elasticsearch implementations.", | ||
"keywords": [ | ||
"Elasticsearch", | ||
"Elastica", | ||
"Symfony", | ||
"Search" | ||
], | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Damien Alexandre", | ||
"homepage": "https://jolicode.com/" | ||
} | ||
], | ||
"require": { | ||
"ruflin/elastica": "^6.1", | ||
"symfony/yaml": "^4.2", | ||
"symfony/serializer": "^4.2", | ||
"symfony/property-access": "^4.2", | ||
"symfony/property-info": "^4.2", | ||
"ext-json": "*", | ||
"php": "^7.2" | ||
}, | ||
"autoload": { | ||
"psr-4": { | ||
"JoliCode\\Elastically\\": "./src" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"JoliCode\\Elastically\\Tests\\": "./tests" | ||
} | ||
}, | ||
"require-dev": { | ||
"friendsofphp/php-cs-fixer": "^2.14", | ||
"phpunit/phpunit": "^8" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
namespace JoliCode\Elastically; | ||
|
||
use Elastica\Client as ElasticaClient; | ||
use Symfony\Component\Serializer\Encoder\JsonEncoder; | ||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; | ||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; | ||
use Symfony\Component\Serializer\Serializer; | ||
use Symfony\Component\Serializer\SerializerInterface; | ||
|
||
class Client extends ElasticaClient | ||
{ | ||
/* Elastically config keys */ | ||
const CONFIG_MAPPINGS_DIRECTORY = 'elastically_mappings_directory'; | ||
const CONFIG_INDEX_CLASS_MAPPING = 'elastically_index_class_mapping'; | ||
const CONFIG_SERIALIZER = 'elastically_serializer'; | ||
const CONFIG_BULK_SIZE = 'elastically_bulk_size'; | ||
|
||
protected $indexer; | ||
|
||
public function getIndexBuilder(): IndexBuilder | ||
{ | ||
return new IndexBuilder($this, $this->getConfig(self::CONFIG_MAPPINGS_DIRECTORY)); | ||
} | ||
|
||
public function getIndexer(): Indexer | ||
{ | ||
if (!$this->indexer) { | ||
$this->indexer = new Indexer($this, $this->getSerializer(), $this->getConfigValue(self::CONFIG_BULK_SIZE, 100)); | ||
} | ||
|
||
return $this->indexer; | ||
} | ||
|
||
public function getIndex($name): Index | ||
{ | ||
return new Index($this, $name); | ||
} | ||
|
||
public function getSerializer(): SerializerInterface | ||
{ | ||
$configSerializer = $this->getConfigValue(self::CONFIG_SERIALIZER, null); | ||
if ($configSerializer) { | ||
return $configSerializer; | ||
} | ||
|
||
// Default | ||
return new Serializer([ | ||
new ArrayDenormalizer(), | ||
new ObjectNormalizer(), | ||
], [ | ||
new JsonEncoder(), | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
|
||
namespace JoliCode\Elastically; | ||
|
||
use Elastica\Index as ElasticaIndex; | ||
use Elastica\ResultSet\BuilderInterface; | ||
|
||
class Index extends ElasticaIndex | ||
{ | ||
protected $builder; | ||
|
||
/* | ||
* Compatibility shortcut, types are no longer needed. | ||
*/ | ||
public function getDocument($id) | ||
{ | ||
return $this->getType('_doc')->getDocument($id); | ||
} | ||
|
||
public function getModel($id) | ||
{ | ||
$document = $this->getDocument($id); | ||
|
||
return $this->getBuilder()->buildModelFromIndexAndData($document->getIndex(), $document->getData()); | ||
} | ||
|
||
public function createSearch($query = '', $options = null, BuilderInterface $builder = null) | ||
{ | ||
$builder = $builder ?? $this->getBuilder(); | ||
|
||
return parent::createSearch($query, $options, $builder); | ||
} | ||
|
||
public function getBuilder(): ResultSetBuilder | ||
{ | ||
if (!$this->builder) { | ||
$this->builder = new ResultSetBuilder($this->getClient()); | ||
} | ||
|
||
return $this->builder; | ||
} | ||
} |
Oops, something went wrong.