Elastic search dynamic aggregation - elasticsearch

I have a index with products type, this product have all some common attributes, but depends on category have different attributes( i make a dinamyc mapping).
How is the best to mapping this and make after aggregation on them without knowing before how this field are named.
[specifications] => Array
(
[properties] => Array
(
[property1] => Array
(
[type] => string
[index] => not_analyzed
)
[property2] => Array
(
[type] => string
[index] => not_analyzed
),
etc...
)
)

I found the solution:
mappping:
'attributes' => array(
'type' => 'nested',
'properties' => array(
'key' => array(
'type' => 'string',
'index' => 'not_analyzed',
),
'value' => array(
'type' => 'string',
'index' => 'not_analyzed',
),
),
),
aggs:
'attributes' => array(
'nested' => array(
'path' => 'attributes',
),
'aggs' => array(
'key' => array(
'terms' => array(
'field' => 'attributes.key',
),
'aggs' => array(
'value' => array(
'terms' => array(
'field' => 'attributes.value',
),
),
),
),
),
),

Multi match queries allows for wildcard fields.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html#CO27-2
You can fiddle with some naming convention or isolate the fields you want to search in an object field (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-object-type.html) and then use the widlcard to target those inner fields.

Related

How to add spinner to select list using ajax programmatically?

I want to add spinner to select list using ajax. I have tried below code for throbber but it's not working for select list.
$form['select choice'] = [
'#type' => 'select',
'#title' => t('Choice'),
'#attributes' => [
'class' => ['js-dop-chosen'],
],
'#options' => [
'---' => t('None'),
t('choice 1'),
t('choice 2'),
],
'#ajax' => [
'event' => 'change',
'wrapper' => 'form-wrapper',
'callback' => [$this, 'ajaxCallback'],
'progress' => [
'type' => 'throbber',
'message' => 'fetching content.....',
],
],
];

Elastica Mapping include_type_name

I'm trying to create a mapping from Elastica.
Here is my code to create my index with params of mapping :
$elasticaClient = new ElasticaClient;
$elasticaIndex = $elasticaClient->getIndex('products');
$elasticaIndex->create(
array(
'settings' => array(
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => array(
'filter' => array(
'french_elision' => array(
'type' => 'elision',
'articles_case' => 'true',
'articles' => array("l", "m", "t", "qu", "n", "s", "j", "d", "c", "jusqu", "quoiqu", "lorsqu", "puisqu"),
),
'french_synonym' => array(
"type" => "synonym",
"ignore_case" => true,
"expand" => true,
"synonyms" => []
),
'french_stemmer' => array(
"type" => "stemmer",
"language" => "light_french"
)
),
'analyzer' => array(
'french_heavy' => array(
'type' => 'custom',
'tokenizer' => 'icu_tokenizer',
'filter' => array('french_elision', 'icu_folding', 'french_synonym', 'french_stemmer', 'asciifolding', 'lowercase')
),
'french_light' => array(
'type' => 'custom',
'tokenizer' => 'icu_tokenizer',
'filter' => array('french_elision', 'icu_folding', 'lowercase', 'asciifolding')
)
)
)
)
),
true
);
$elasticaType = $elasticaIndex->getType('product');
$mapping = new $mapping = new ElasticaTypeMapping;
$mapping->setType($elasticaType);
$mapping->setParam('index_analyzer', 'french_heavy');
$mapping->setParam('search_analyzer', 'french_light');
$mapping->setProperties(
array(
'name' => array(
'type' => 'string',
'boost' => 4
),
'description' => array(
'type' => 'string',
'boost' => 2
),
)
);
$mapping->send();
But I'm having the following error:
Types can not be provided in put mapping requests, unless the include_type_name parameter is set to true.
I can't find how to pass "include_type_name = true" in Ruflin/Elastica.
All my searches return examples in CURL ..
Thank a lot to help me
You seem to be running ES7 and include_type_name is false by default.
You can prevent that error from occurring by changing the last line with this one:
$mapping->send(['include_type_name' => true]);
It's WORK !!
Here is my config :
PHP 7.3.4
Symfony 4.3
Elasticsearch 7.0.1
composer require elasticsearch/elasticsearch "dev-master"
composer require ruflin/elastica "dev-master"
$elasticaClient = new ElasticaClient;
$elasticaIndex = $elasticaClient->getIndex('products');
$elasticaType = $elasticaIndex->getType('product');
$elasticaIndex->create(
array(
'settings' => array(
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => array(
'filter' => array(
'french_elision' => array(
'type' => 'elision',
'articles_case' => 'true',
'articles' => array("l", "m", "t", "qu", "n", "s", "j", "d", "c", "jusqu", "quoiqu", "lorsqu", "puisqu"),
),
'french_synonym' => array(
"type" => "synonym",
"ignore_case" => true,
"expand" => true,
"synonyms" => []
),
'french_stemmer' => array(
"type" => "stemmer",
"language" => "light_french"
),
),
'analyzer' => array(
'french_heavy' => array(
'type' => 'custom',
'tokenizer' => 'icu_tokenizer',
'filter' => array('french_elision', 'icu_folding', 'french_synonym', 'french_stemmer', 'asciifolding', 'lowercase')
),
'french_light' => array(
'type' => 'custom',
'tokenizer' => 'icu_tokenizer',
'filter' => array('french_elision', 'icu_folding', 'lowercase', 'asciifolding')
),
)
)
)
),
true
);
$mapping = new ElasticaTypeMapping;
$mapping->setType($elasticaType);
$mapping->setProperties(
array(
'name' => array(
'type' => 'text',
'analyzer' => 'french_heavy',
'boost' => 4
),
'description' => array(
'type' => 'text',
'analyzer' => 'french_light',
'boost' => 2
),
)
);
$mapping->send(['include_type_name' => true]);

How to configure an entity as part of the second-level cache in DoctrineORMModule?

I was trying to configure memcached in DoctrineORM module of my Zendframework 2 project to perform caching queries, results and metadata follow this tutorial https://github.com/doctrine/DoctrineORMModule/blob/master/docs/cache.md
In module.config.php
<?php
return array(
'service_manager' => array(
'invokables' => array(
// ...
),
'factories' => array(
'doctrine.cache.my_memcached' => function ($sm) {
$cache = new \Doctrine\Common\Cache\MemcachedCache();
$memcache = new Memcached();
$memcache->addServer('localhost', 11211);
$cache->setMemcached($memcache);
return $cache;
},
'MemcachedFactory' => \Application\Service\Cache\MemcachedFactory::class,
)
),
'doctrine' => array(
'cache' => array(
'memcached' => array(
'namespace' => '_Doctrine',
'instance' => 'MemcachedFactory',
),
),
'configuration' => array(
'orm_default' => array(
'query_cache' => 'memcached',
'result_cache' => 'memcached',
'metadata_cache' => 'memcached',
'hydration_cache' => 'memcached',
'second_level_cache' => [
'enabled' => true,
'default_lifetime' => 200,
'default_lock_lifetime' => 500,
'file_lock_region_directory' => './data/cache',
'regions' => [
'My\FirstRegion\Name' => [
'lifetime' => 800,
'lock_lifetime' => 1000
],
'My\SecondRegion\Name' => [
'lifetime' => 10,
'lock_lifetime' => 20
],
],
],
),
),
'driver' => array(
'_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'my_memcached',
'paths' => array(__DIR__ . '/../src/Application/Entity')
),
'orm_default' => array(
'drivers' => array(
'Application\Entity' => '_driver'
),
),
),
),
);
and after I create a method as the following:
public function findById($id) {
$qb = $this->entityManager->createQueryBuilder();
$qb->select("u")
->from(User::class, "u")
->where($qb->expr()->eq("u.id", ":id"))
->setParameter("id", (int) $id);
return $qb->getQuery()->setCacheable(true)->getOneOrNullResult();
}
and after, I get a Doctrine\ORM\Cache\CacheException
with message:
Entity "Application\Entity\User" not configured as part of the second-level cache.
Anyone who can suggest for me to solved this problem?
Add this to the USER class:
* #ORM\Cache(usage="NONSTRICT_READ_WRITE")

Symfony 1.4 doctrine create table

Can someone show me an example on how to use the createTable in Doctrine?
For example, I'd like to create a table 'attachment' with the following columns:
'file_path' =>string
'message_id'=>integer
Thanks
Found it :
$this->createTable('attachment', array(
'id' =>
array(
'type' => 'integer',
'length' => 8,
'autoincrement' => true,
'primary' => true,
),
'file_path' =>
array(
'type' => 'string',
'notnull' => true,
'length' => 255,
),
'message_id' =>
array(
'type' => 'integer',
'notnull' => false,
'length' => 8,
),
'created_at' =>
array(
'notnull' => true,
'type' => 'timestamp',
'length' => 25,
),
'updated_at' =>
array(
'notnull' => true,
'type' => 'timestamp',
'length' => 25,
),
), array(
'indexes' =>
array(
),
'primary' =>
array(
0 => 'id',
),
'collate' => 'utf8_general_ci',
'charset' => 'utf8',
));

Elastica filter not working

I am testing out Elastica and Elastic Search. I am trying to add a filter to my query that only returns results by city location. It is returning empty. I've tried filter by username, and so on and it always returns empty, so it would seem my understanding isn't quite correct. Here's my code to analyse, map, then search with a filter
$elasticaIndex = $elasticaClient->getIndex('users');
// Create the index new
$elasticaIndex->create(
array(
'analysis' => array(
'analyzer' => array(
'indexAnalyzer' => array(
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => array('lowercase', 'lb_ngram')
),
'searchAnalyzer' => array(
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => array('standard', 'lowercase', 'lb_ngram')
)
),
'filter' => array(
'lb_ngram' => array(
"max_gram" => 10,
"min_gram" => 1,
"type" => "nGram"
)
)
)
), true
);
//Create a type
$elasticaType = $elasticaIndex->getType('profile');
// Set mapping
$mapping->setProperties(array(
//'id' => array('type' => 'integer', 'include_in_all' => FALSE),
'firstName' => array('type' => 'string', 'include_in_all' => TRUE),
'lastName' => array('type' => 'string', 'include_in_all' => TRUE),
'username' => array('type' => 'string', 'include_in_all' => TRUE),
'bio' => array('type' => 'string', 'include_in_all' => TRUE),
'thumbnail' => array('type' => 'string', 'include_in_all' => FALSE),
'location' => array('type' => 'string', 'include_in_all' => TRUE),
));
..... Then to search, I do the following
$elasticaQueryString = new Elastica\Query\QueryString();
//'And' or 'Or' default : 'Or'
$elasticaQueryString->setDefaultOperator('AND');
$elasticaQueryString->setQuery($term);
// Create the actual search object with some data.
$elasticaQuery = new Elastica\Query();
$elasticaQuery->setQuery($elasticaQueryString);
To add a filter
$elasticaFilterLocation = new \Elastica\Filter\Term();
//search 'location' = $region;
$elasticaFilterLocation->setTerm('location', $region);
$elasticaQuery->setFilter($elasticaFilterLocation);
$elasticaResultSet = $elasticaIndex->search($elasticaQuery);
$elasticaResults = $elasticaResultSet->getResults();
If I comment out the filter, I do get the expected results. What am I missing? Does it have to do with the analyzer or mapping?
I had the same issue, I fixed it by changing my analyzers for these fields in the mappings. Now I have to rebuild my indexes etc... Don't try to find a solution to change mapping or analyzer without rebuilding your index, you can't.
lc_analyzer' => array(
'type' => 'custom',
'tokenizer' => 'keyword',
'filter' => array('lowercase')
),
For mapping:
'location' => array('type' => 'string', 'analyzer' => 'lc_analyzer'),
Then, query like
$elasticaFilterBool = new \Elastica\Filter\Bool();
$filter1 = new \Elastica\Filter\Term();
$filter1->setTerm('location', array(strtolower($region)));
$elasticaFilterBool->addMust($filter1);
$elasticaQuery->setFilter($elasticaFilterBool);
I think your location is being tokenized on spaces and commas so it is killing the search. should solve it for you.

Resources