How to perform a Prefix query with Elastica - symfony

I'm attempting to create an autocomplete search using Elastica and Elastic Search (more specifically, FOSElasticaBundle for Symfony2).
I've created a simple index, populated it with objects.
A basic search works, ie:
$finder = $this->container->get('fos_elastica.finder.search.person');
$results = $finder->find('Mike');
I'm having some trouble getting my prefix query to work though and I can't find any examples online. Here's what I'm trying:
$finder = $this->container->get('fos_elastica.finder.search.person');
$prefixQuery = new \Elastica\Query\Prefix();
$prefixQuery->setPrefix('nameFirst','Mik');
$results = $finder->find($prefixQuery);
It doesn't kick any errors, but just doesn't return any results.
The field should be set properly...my configuration looks like this:
...
types:
person:
mappings:
nameFirst: { boost: 10 }
nameLast: { boost: 10 }
nameMiddle: { boost: 3 }
...
Can anyone tell what I'm doing wrong?
Also: Bonus Question: Is the best way to search the prefix on both the nameFirst AND nameLast fields going to be using a NestedQuery, or using addParam() to add both the nameFirst and nameLast?
Thanks a bunch-

Related

ElasticSearch filter by wildcard

I'm trying to filter my results by wildcard character.
example of my records:
....
"_source" : {
"urlSlug" : "entry-title",
"revisions" : [
{
"title" : "Entry title",
"context" : "NKD"
}
]
}
each revision can have different context with different order.
And when I search for record I want to search only entities with context like "N". So I perform nested query with match_all and wildcard.
{"query":{"bool":{"must":[{"query_string":{"query":"*entry*"}},{"nested":{"path":"revisions","query":{"bool":{"should":[{"match_all":{}}],"filter":[{"wildcard":{"revisions.context":{"value":"*N*","boost":1}}}]}}}}]}},"size":10}
When I run query I get zero results. And Can't figure out how to restrict results.
I'm using for this FosElastica with following config:
indexes:
app:
types:
entity:
properties:
urlSlug: ~
revisions:
type: "nested"
properties:
title: { type: text,boost: 10 }
context: { type: text }
and my query builder looks like this:
$boolQuery = new ESQuery\BoolQuery();
$fieldQuery = new ESQuery\QueryString();
$fieldQuery->setQuery('*' . $query . '*');
$boolQuery->addMust($fieldQuery);
$nestedQuery = new ESQuery\Nested();
$nestedQuery->setPath('revisions');
$nestedBoolQuery = new ESQuery\BoolQuery();
$matchAllQuery = new ESQuery\MatchAll();
$nestedBoolQuery->addShould($matchAllQuery);
$filterQuery = new ESQuery\Wildcard();
$filterQuery->setValue('revisions.context','*N*');
$nestedBoolQuery->addFilter($filterQuery);
$nestedQuery->setQuery($nestedBoolQuery);
$boolQuery->addMust($nestedQuery);
$result = $finder->findHybrid($boolQuery,self::AUTOCOMPLETE_MAX_RESULTS);
ElasticSearch version 5.2.2
Well I did find out what is the problem in my query.
this is working one:
{"query":{"bool":{"must":[{"query_string":{"query":"*komi*"}}],"filter":[{"nested":{"path":"revisions","query":{"wildcard":{"revisions.context":{"value":"*n*","boost":1}}}}}]}},"size":10}
whole problem was uppercase wildcard search. I was looking for *N* and have zero results and with *n* it fine.

Call setter method with variable name

What I'm asking here is something weird. I'm using Symfony2 with Doctrine2. To bypass a issue between FOSRestBundle and JMSBundle (who don't like composite primary key) I need to know if it's possible - and how - to call a setter from the name of the field.
Here an example: imagine my Product entity have a primary key composed by 3 fields.
The trick is to send an array this kind of JSON into my API REST:
{
"id": {
"field1": "xxx",
"field2": "...",
"field3": "..."
},
// other fields
}
Then I use json_decode() to extract the ID field. I create a table of $key => $value with the 3 primary keys. And there is my problem, with this table I want, in a foreach loop, to do something like $myEntity->set$KEY($VALUE).
I'm doing this because I want to reuse this code with all my entities.
I know that this is something really weird, to sum up with only the name of the object field/property I want to call is appropriate setter().
Thanks ;-)
PS: sorry if my English isn't perfect, this isn't my birth langage.
You can use dynamic method name in PHP :
$myEntity->{'set'.$KEY}($VALUE);
or more readable version :
$method = 'set'.$KEY;
$myEntity->$method($VALUE);
Don't forget to check if method exists anyway :
$method = 'set'.$KEY;
if (!method_exists($myEntity, $method))
throw new \Exception('Something bad');
$myEntity->$method($VALUE);

Symfony2 Gedmo Translatable with APY DataGrid and KNP Paginator

I have a few problems using Gedmo\DoctrineExtensions Translatable.
First is APY DataGrid - can't make it to show translated strings in grid on non default locale. If I use Translatable with default settings, all strings in grid are displayed in default language. If I implement Translatable in Entity and add annotations for table and other stuff, then I can see translated strings in grid, BUT after switching locales these stays the same. Seems like QueryCache is used, but can't find how to set not to use it. Here's a part for grid:
use APY\DataGridBundle\Grid\Source\Entity;
<...>
$source = new Entity('MainBundle:Entity');
$source->addHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
Of course it would be better to have translations without making annotations and separate entities for them.
Second problem is KNP pagination. Actually didn't dig into it, but similar problem.
The main problem is, when I run some query by translatable field of an entity. Let's say I have an Entity with name Krepšinis (it's basketball in Lithuanian) and I have translated this string to Basketball. Default language is LT. When in default language I perform a search, everything is ok, but if I change locale to EN and try searching for basket, it doesn't return any results and if I search for krep, it returns me Basketball. Code for search:
// Controller
$repository = $this
->getDoctrine()
->getManager()
->getRepository('MainBundle:Entity');
$query = $repository
->search($term)
->getQuery()
->useQueryCache(false)
->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
// Repository
public function search($query)
{
$qb = $this->createQueryBuilder('t');
$term = $qb->expr()->literal('%' . $query . '%');
$query = $qb->where($qb->expr()->like('t.name', $term));
return $query;
}
Any help is appreciated
if content is translated, you need to use query hints as you have already went through. But in order to have it cached for different locales, you need to set the locale hint to the query:
<?php
// hint the locale in order to make query cache id unique
$query->setHint(
\Gedmo\Translatable\TranslatableListener::HINT_TRANSLATABLE_LOCALE,
'en' // take locale from session or request
);
Which is described in the documentation read it carefully.
ORM query cache is based on DQL, query parameters and query hints.

Doctrine Translatable how to only fetch records with a translation

I'm using Symfony2 + Doctrine + Translatable from DoctrineExtensions.
I have an entity article which has a couple of translatable fields like Title and Content. What is happening now is that I've created a bunch of articles in Chinese language, but have not added a translation for English. This is giving me some problems when I try to display a top 8 most recent articles on my homepage... When I view my homepage in English, it will show a bunch of title-less articles there (the Chinese articles that dont have a translation in English).
I found a solution for this in the Translatable extension by using ORM query Hint:
"\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER".
This lets you directly query the translated fields of your entity which are actually stored in ext_translations and not in the entity's table.
As a result the code I use to fetch the articles for the homepage looks like this:
public function getNewestArticles($limit = 1){
$dql =
"SELECT a FROM NewsBundle:Article a
WHERE a.published = 1
AND a.title != ''
ORDER BY a.created_at DESC";
$query = $this->_em->createQuery($dql);
$query->setMaxResults($limit);
$query->setHint(
\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER,
'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker'
);
$result = $query->getResult();
return $result;
}
This actually works, but the generated query is so inefficient that it slows down the page a lot... I'm talking 1800 ms for that query. I've also tried to just put the fields I need in the select statement, which improves the performance, but still not enough.
Any ideas?
you can try to optimize the query manually. use locale as the parameter in your repository
public function getNewestArticles($locale, $limit = 1){
//your own superfast query
}
in the controller then set the locale with
$locale = $request->getLocale();
$em->getNewestArticles($locale, $limit);
additional question: have you set indexes on your tables?

Database Searching Using Doctrine and Symfony2

So I'm currently trying to perform a simple search using Symfony2 and Doctrine. Something similar to this: http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/searching.html
I've currently got the following YAML file setup to generate my entities. It generates my class Style entity correctly as a class.
...\Style:
type: entity
table: styles
id:
id:
type: integer
generator:
strategy: IDENTITY
actAs:
Searchable:
fields: [title]
batchUpdates: true
fields:
title:
type: string
length: 150
unique: true
In my controller, I'm trying to run a search on that table based on a string.
public function searchAction($pattern)
{
$repository = $this->getDoctrine()->getRepository('..:Style');
$search = $repository->search($pattern);
return $this->outputize($search);
}
However, when I try executing the code, I get the following exception.
Undefined method 'search'. The method name must start with either findBy or findOneBy!
Am I generating my entities correctly or is there something I'm clearly missing?
On a side note, when I look at my Entity/Style.php after generating, there is no clear method ->search(), is the function supposed to be generated by Symfony here?
search() is not a function supported in Symfony2. You're looking at the Symfony 1.x documentation, and Symfony2 is really different from Symfony 1.x so for reference, you should always use the doc.
There are several ways to fetch entities in Symfony2. Here are a few examples:
Find
$user = $this->getDoctrine()
->getRepository('UserBundle:User')
->find($user_id)
;
DQL:
$query = $em->createQuery(
'SELECT b FROM YourBundle:Bid b WHERE b.property_id = :property_id ORDER BY b.amount DESC'
)->setParameter('property_id', $property_id);
try {
$bids = $query->getResult();
} catch (\Doctrine\Orm\NoResultException $e) {
//Handle No Result Exception here
}
Refer to the Doctrine guide for Symfony2 here: http://symfony.com/doc/current/book/doctrine.html
Hello you can do it in symfony 3
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
'SELECT p
FROM AppBundle:Hotel p
WHERE p.address like :location
ORDER BY p.address ASC'
)->setParameter('location','%'.$request->get('location').'%' );
$hotel = $query->getResult();

Resources