Elastic Searching With
PHP
Lea Hänsenberger - @lea_h
Liip AG – Agile Web Development – Fribourg, Zürich, Bern
About me – work life
smartvote.ch
Web Developer at Liip AG for 3 years
About me – the other life
Aerobatics Paragliding Pilot
Elastica
FOSElasticaBundle
elasticsearch
Lucene
Full text
search
Document oriented
RESTful
API
Schema free
http://elasticsearch.org
elasticsearch – full text
search
Based on Lucene
„Apache LuceneTM is a high-performance, full-featured
text search engine library written entirely in Java. It is
a technology suitable for nearly any application that
requires full-text search, especially cross-platform.“
elasticsearch – full text
search
Multi-language support
Geolocation
Did-you-mean suggestions
Autocomplete
and a lot more...
elasticsearch – document
oriented
Entities as structured JSON documents
All fields indexed by default
{
"field" : "value"
}
elasticsearch – schema free
All fields indexed by default
Detecting data structure
{
"name" : "Peter",
"age" : 22
}
elasticsearch – RESTful API
JSON over HTTP
elasticsearch – RESTful API
–
Add/update document
$ curl -XPUT 'http://localhost:9200/phpday/speaker/1'
-d '{
"firstname" : "John",
"lastname" : "Doe",
"speeches" : 2
}'
{
"ok" : true,
"_index" : "phpday",
"_type" : "speaker",
"_id" : "1",
"_version" : 1
}
Request
Response
elasticsearch – RESTful API
–
Delete document
$ curl -XDELETE 'http://localhost:9200/phpday/speaker/1'
{
"ok" : true,
"_index" : "phpday",
"_type" : "speaker",
"_id" : "1",
"found" : true
}
Request
Response
elasticsearch – RESTful API
–
Field Mapping
$ curl -XPUT 'http://localhost:9200/phpday/speaker/_mapping'
-d '
{
"speaker" : {
"properties" : {
"firstname" : { "type" : "string" },
"lastname" : { "type" : "string" },
"speeches" : { "type" : "integer" }
}
}
}'
elasticsearch – RESTful API
–
Search
$ curl -XGET 'http://localhost:9200/phpday/speaker/_search'
-d '{
"query":{
"bool":{
"should":[
{
"query_string":{
"default_field":"_all",
"query":"John"
}
}
]
}
}
}'
Request
elasticsearch – RESTful API
–
Search
{
...
"hits":{
...
"hits":[
{
...
"_source":{
"firstname":"John",
"lastname":"Doe",
"speeches":2
}
}
]
}
}
Response
Elasticsearch - Tools
Browser/Querying
http://mobz.github.io/elasticsearch-head/
Elastica
http://elastica.io
PHP client
elastica - Connect
$elasticaClient = new ElasticaClient();
$elasticaClient = new ElasticaClient(array(
'host' => 'otherhost.org',
'port' => 12345,
));
elastica - Prepare
// Load index
$elasticaIndex = $elasticaClient->getIndex('phpday');
// Create a type
$elasticaType = $elasticaIndex->getType('speaker');
elastica – Add/update
document
$doc = new ElasticaDocument(1, array(
'firstname' => 'John',
(...)
));
$elasticaType->addDocument($doc);
$elasticaIndex->refresh();
elastica – Bulk indexing
/* @var array ElasticaDocument */
$docs = array();
$docs[] = ...
$elasticaType->addDocuments($docs);
$elasticaIndex->refresh();
elastica – Add object
$elasticaType->setSerializer($callable);
$elasticaType->addObject($object, $elasticaDoc);
Configure serializer Object -> Array
Add objects directly
elastica – Delete document(s)
$elasticaType->deleteDocument($elasticaDoc);
$elasticaType->deleteById($id);
$elasticaType->deleteIds($ids);
$elasticaType->deleteByQuery($elasticaQuery);
elastica – Field mapping
$mapping = new ElasticaTypeMapping();
$mapping->setType($elasticaType);
$mapping->setProperties(array(
'firstname' => array('type' => 'string'),
(...)
));
$mapping->send();
Index must exist!
elastica – Search
$elasticaQueryString = new ElasticaQueryQueryString();
$elasticaQueryString->setQuery('John');
Define the query
elastica – Search
$elasticaQuery = new ElasticaQuery();
$elasticaQuery->setQuery($elasticaQueryString);
$resultSet = $elasticaType->search($elasticaQuery);
Create the actual search object
Search on type or index
elastica – Search
$elasticaQuery->setFilter($elasticaFilter);
$elasticaQuery->addFacet($elasticaFacet);
...
Filters, facets, etc. are added to the search object
FOSElasticaBundle
Symfony 2 Bundle
http://git.io/foselasticabundle
elastica
FOSElasticaBundle
Moved to FOS namespace recently
Formerly known as FOQElasticaBundle
FOSElasticaBundle –
Configuration
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
phpday:
client: default
types:
speaker: ~
FOSElasticaBundle –
Add/update documents
Automatic provider for Doctrine, MongoDB, Propel
Manual provider
or: just use elastica
FOSElasticaBundle –
Add/update – Automatic
Config:
! Mapping required
fos_elastica:
...
speaker:
mappings:
firstname: {type: string}
persistence:
driver: orm
model: LiipPhpdayBundleEntitySpeaker
provider: ~
FOSElasticaBundle –
Add/update – Automatic
Run command:
$ app/console fos:elastica:populate
FOSElasticaBundle –
Add/update – Automatic
SpeakerRepository::getSpeakers() returns
QueryBuilder
No propel support yet!
fos_elastica:
...
speaker:
...
persistence:
...
provider:
query_builder_method: getSpeakers
FOSElasticaBundle –
Add/update – Manual
Provider
Remove persistence configuration
Define service for provider class
services:
liip_phpday.search_provider.speaker:
class: LiipPhpdayBundleProviderSpeakerProvider
tags:
- {name: fos_elastica.provider,index: phpday,type: speaker}
arguments: [ @fos_elastica.index.phpday.speaker ]
FOSElasticaBundle –
Add/update – Manual
Provider
Manually create and add elastica documents
class SpeakerProvider implements ProviderInterface
{
function populate(Closure $loggerClosure = null)
{
...
}
}
FOSElasticaBundle –
Delete Document
Use elastica directly
or: use populate command to completely reindex
FOSElasticaBundle – Search
Using elastica
/** var ElasticaType */
$speakerType = $this->container
->get('fos_elastica.index.phpday.speaker');
/** var ElasticaResultSet */
$results = $speakerType->search('MariaSymfony');
FOSElasticaBundle – Search
Getting back Doctrine/Propel Entities
fos_elastica:
...
mappings: ...
persistence:
driver: orm
model: LiipPhpdayBundleEntitySpeaker
provider: ~
finder: ~
FOSElasticaBundle – Search
Getting back Doctrine/Propel Entities
/** var FOSElasticaBundleFinderTransformedFinder */
$finder = $this->container
->get('fos_elastica.finder.phpday.speaker');
/** var array of LiipPhpdayBundleEntitySpeaker */
$speakers = $finder->find('MariaSymfony');
FOSElasticaBundle – Search
Custom queries
fos_elastica:
...
mappings: ...
persistence:
driver: orm
model: LiipPhpdayBundleEntitySpeaker
provider: ~
finder: ~
repository: ...SearchSpeakerRepository
FOSElasticaBundle – Search
Custom queries
class SpeakerRepository extends FOSElasticaBundleRepository
{
public function findWithCustomQuery($searchTerm)
{
// build query with Elastica objects
return $this->find($searchTerm);
}
}
FOSElasticaBundle – Search
Custom queries
/** var FOSElasticaBundleManagerRepositoryManager */
$repositoryManager = $this->container
->get('fos_elastica.manager');
/** var FOSElasticaBundleRepository */
$repository = $repositoryManager
->getRepository('LiipPhpdayBundle:Speaker');
/** var array of LiipPhpdayBundleEntitySpeaker */
$results = $repository->findWithCustomQuery('MariaSymfony');
FOSElasticaBundle – And
more...
Live index updates
Advanced elasticsearch configuration
Paged search
...
=> http://git.io/foselasticabundle
Elastica
FOSElasticaBundle
?

Elastic Searching With PHP

Editor's Notes

  • #12 Index automatically created if not existing Id auto-generated if not in URL
  • #20 If index does not exist yet, nothing happened so far But no error either
  • #21 At this point the index is created if it did not exist before
  • #23 Second argument is optional, in case you want to define the id of the document