Adding filter to DateHistogram aggregation in ruflin/elastica - elastica

Ok, I am a bit confused.
I create aggregation as follows:
$aggregation = new DateHistogram('clicks_by_day', 'date', 'day');
$query->addAggregation($aggregation);
Now in this aggregation, I want to apply range filter to this aggregation. (Clicks with price greater then 0).
So I am a bit confused how to actually do it? There is no setFilter method, which I though would be the way to do it.
Anyone can help me with this?

Found out myself, here how it works:
Create Filter:
$filter = new Filter('paid', new Query\Range('price', ['gt' => 0]));
Create aggregation:
$aggregation = new DateHistogram('clicks_by_day', 'date', 'day');
Add aggregation to filter:
$aggregation = $filter->addAggregation($aggregation);
The last step returns the aggregation with filter applied. Ant it work as expected.

Related

Search multiple indices against some index pattern using NEST

I searched NEST docs but seems to cant find a proper answer for it.
My question is how to search multiple indices against some index pattern using NEST? e.g
if I have indices with following names in Elasticsearch DB
media-2017-10, media-2018-03, media-2018-04
For specifying my selected indices, I need to use wild card character * like this:
client.Search<Media>(s => s
.Index("media-*")
. query goes here .....
Is it possible in NEST ?
Yes, this works. Try it :)
.Index(...) accepts wildcard indices
You can also search in multiple indices in that way:
var allIndices = new[] {
"media-*",
"docs-*",
"common-*"
};
Nest.Indices allIndices = allIndices;
return _elasticClient
.SearchAsync<EsBaseModel>(s => s
.Index( allIndices)
.Size(_esConfig.MaxCallIDsSize)
.RequestConfiguration(r => r.RequestTimeout(TimeSpan.FromMinutes(5)))
.Query(q =>
q.Match(m => m.Field("fieldname").Query(condition))
));
Steps:
Just create an array with string indices.
Indices can be explicit or implicit using any pattern supported in Nest client docs.
Notice - neet to put attention to optimize the searching, since it could take a while to search in all the indices that you've provided.
(optimize can be achieved by ignoring very old dates, limit the results, etc...)

The method filter(FilterBuilder) in the type FilterAggregationBuilder is not applicable for the arguments (BoolQueryBuilder)

Am trying to group and subgroup in an elastic query, first by ipgroup and then by priority.
TermsBuilder ipGroupAgg = AggregationBuilders.terms("by_ipGroup").field("IP Group")
.subAggregation(AggregationBuilders.terms("by_Priority").field("Priority"));
// create the bool filter for the condition above
String[] priority= { "2", "3" };
BoolQueryBuilder aggFilter = QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("Priority", priority));
// create the filter aggregation and add the year sub-aggregation
FilterAggregationBuilder aggregation = AggregationBuilders.filter("agg").filter(aggFilter).subAggregation(ipGroupAgg );
But the last statement gives compile error stating "The method filter(FilterBuilder) in the type FilterAggregationBuilder is not applicable for the arguments (BoolQueryBuilder)" for the filter(aggFilter)
You're probably using an old version of ES, my guts tell me 1.7 or earlier...
In this case you need to use the following code to create aggFilter:
BoolFilterBuilder aggFilter = FilterBuilders.boolFilter().must(FilterBuilders.termsFilter("Priority", priority));

Paginate in elasticsearch

I am new to elasticsearch and at least for the flask extension (flask-elasticsearch) the documentation is very bad. Any help is much appreachiated.
I have a elasticsearch query which looks like this
res = es.search(index="user-index", from_=(page-1)*10, size=10, body={"query": {"match_all": {}}})
I query the user table and want only 10 results. Now I still have to get the actual table rows. So I query them like this
list_of_ids = []
for hit in res['hits']['hits']:
list_of_ids.append(hit["_id"])
search_result = models.User.query.filter(models.User.id.in_(list_of_ids)).paginate(page, 10, False)
as you can see I am using the paginate() function. However, since I passed a list of 10 ids into the query, the paginate function does not know about the total number of results in the search query. So the paginate function can't work this way...
I could just do all the paginate functionality by myself, but I was wondering whether there is a nice way to keep the paginate functionality and somehow link it with the elastic search?
thanks
carl
I found a solution... its possible to just assign the relevant pagination values like
search_result.total = res['hits']['total']
search_result.page = page
cheers

FOSElasticaBundle order query

I am integrating FOSElasticaBundle in my Symfony 2.3 project and I need to sort the results by their price property.
Here is my code:
$finder = $this->container->get('fos_elastica.finder.website.product');
$fieldTerms = new \Elastica\Query\Terms();
$fieldTerms->setTerms('taxon_ids', $taxon_ids_array);
$boolQuery->addMust($fieldTerms);
$resultSet = $finder->find($boolQuery);
How I can do this?
Thanks
Try create a \Elastica\Query object which also contains the sorting information, then send this to the finder:
$finder = $this->container->get('fos_elastica.finder.website.product');
$fieldTerms = new \Elastica\Query\Terms();
$fieldTerms->setTerms('taxon_ids', $taxon_ids_array);
$boolQuery->addMust($fieldTerms);
$finalQuery = new \Elastica\Query($boolQuery);
$finalQuery->setSort(array('price' => array('order' => 'asc')));
$resultSet = $finder->find($finalQuery);
Have a look at the elasticsearch docs on the sort parameter to see how to use it properly.
NOTE: \Elastica\Query is quite different to \Elastica\Query\AbstractQuery, the first encapsulates everything you could send to the _search API endpoint (facets, sorting, explain, etc...) The AbstractQuery represents a base type for each of the individual query types (range, fuzzy, terms, etc...).

How and where to modify Magento search query?

First of all, I found similar questions in SO but there is not any answer for them. So, the first part of the question is a little bit duplicated. I want to improve search results in Magento. Here is what I've done already:
1. Search with AND instead of OR when there are multiple words.
2. Ajax search starts searching from anywhere and not only from the beginning of the fields.
3. Trim the last s from the words to prevent empty results when searching with plurals.
4. I changed the search type from Like to Fulltext or Combine but the results were not better and even were worst, so I leave it as is. It's Like now, so there is no relevance ordering.
The last thing which I want to try is adding this to the search query:
SELECT ... other non-full-text-cols
MATCH (product_title) AGAINST ('lean body for her') AS rel1,
MATCH (content) AGAINST ('lean body for her') AS rel2
FROM table
WHERE MATCH (product_title,content) AGAINST ('lean body for her')
ORDER BY (rel1*1.5)+(rel2)
Here is my query but I'm not sure if it would work because I can't test it:
$this->_productCollection->addAttributeToSelect(
array(
'rel1' => new Zend_Db_Expr('MATCH (name) AGAINST ("'.$queryText.'")'),
'rel2' => new Zend_Db_Expr('MATCH (short_description) AGAINST ("'.$queryText.'")')
)
);
$this->_productCollection->getSelect()
->where('MATCH (name,short_description) AGAINST ("'.$queryText.'")')
->order('(rel1*1.5)+(rel2)');
The main idea is to add bonus weight to a result if the search query is found in the title of the product. The problem is that I don't know where to modify the query. I can't find where it is at all. $this->_productCollection is not the right object, I know it. I looked at all the Collection.php files, resource models, models and even the query log but no luck. There are just little 1 or 2 row parts in some files but not a full query. I'm new to Magento and still have problems with finding this type of stuff. So, where I have to place my additional stuff when I have to extend a query?
Community Edition Magento, version 1.6.1.0.
Note: I know that some extension for improving search results will work much better than my solutions but for now I have to do it in that way. It would be a good experience for me, too.
Edit:
So, I figured out how to add my custom fields for the ordering but it's
untruly I think. In class Mage_CatalogSearch_Model_Layer extends Mage_Catalog_Model_Layer's prepareProductCollection method I added two joins to the query and get the fields rel1 and rel2:
$collection->getSelect()->joinLeft(
array('cpev' => 'catalog_product_entity_varchar'),
'cpev.entity_id = e.entity_id AND cpev.attribute_id = 96',
array('rel1' => new Zend_Db_Expr('2.01*(LENGTH(cpev.value) - LENGTH(REPLACE(LCASE(cpev.value), LCASE("'.$queryText.'"), ""))) / LENGTH("'.$queryText.'")'))
);
$collection->getSelect()->joinLeft(
array('cpet' => 'catalog_product_entity_text'),
'cpet.entity_id = e.entity_id AND cpet.attribute_id = 506',
array('rel2' => new Zend_Db_Expr('(LENGTH(cpet.value) - LENGTH(REPLACE(LCASE(cpet.value), LCASE("'.$queryText.'"), ""))) / LENGTH("'.$queryText.'")'))
);
I have these fields now but as you can see I have hard coded stuff like attribute_id = 96 etc. which is not good at all and it will not work everytime - I checked these ids directly from the database tables. I wrote it like this because I haven't access to name and short_description fields but they are in the result. Don't know why. So, cpev.value is name field and cpet.value is the short_description field. Moreover I can't order the results by these fields. I tried $collection->addOrder('SUM(rel1+rel2)');, $collection->getSelect()->order(new Zend_Db_Expr('SUM(rel1+rel2)').' DESC');, some addAttributeToFilter stuff etc. but it's not working.
Edit 2:
I accepted #james' answer but finally we bought an extension for improving the search results.
In Mage_CatalogSearch_Model_Resource_Fulltext check out prepareResult (line 310 in 1.7 CE) and look for the following:
$select->columns(array('relevance' => new Zend_Db_Expr(0)));
Magento sets all search result relevances as 0 (!); add the relevances you want (higher is better) here. You can create a custom query in Zend_Db_Expr() to generate higher relevances on attribute matches.
The answer to your first question (1):
To make an AND search instead of OR, you will need to rewrite the class
Mage_CatalogSearch_Model_Resource_Fulltext
In the method
public function prepareResult($object, $queryText, $query)
you want to switch the part
$likeCond = '(' . join(' OR ', $like) . ')';
to
$likeCond = '(' . join(' AND ', $like) . ')';
Be sure to reindex the search index afterwards to have an effect.

Resources