FOSElasticaBundle order query - elasticsearch

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...).

Related

Elasticsearch NEST Document count for default index

I am using NEST for Elasticsearch 6 and would like to get the number of documents for the default index.
The documentation refers to the 1.1 version of the API which no longer seems to work.
I have created the connection settings using a default index:
var connectionSettings = new ConnectionSettings().DefaultIndex("test_docs");
When I try the code from the 1.1 api documentation:
var result = client.Count();
I get the following error:
The type arguments for method
'ElasticClient.Count(Func, ICountRequest>)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly.
When I supply a type it is appended to the path. For example:
client.Count<TestDocument>();
Generates a URL of http://localhost:9200/test_docs/testdocument/_count when what I really need is http://localhost:9200/test_docs/_count
For those needing the new way of doing this (like myself). I would use the following to get a count from a specific index.
var countRequest = new CountRequest(Indices.Index("videos"));
long count = (await _ecClient.CountAsync(countRequest)).Count;
You can use
var countResponse = client.Count<TestDocument>(c => c.AllTypes());
which will call the API
GET http://localhost:9200/test_docs/_count

How can I use X.PagedList with ElasticSearch Nest?

Background
I'm using ElasticSearch as the search engine for a new ASP.Net Core 2.1 website I'm working on. I'm using the Nest API to integrate with it. I want to use the X.PagedList to handle the paging for me.
I've used this in other ASP.Net Core projects and it's worked well querying data in MS SQL Server.
Code
ISearchResponse<Foo> searchResponse =
_elasticSearchClient.Search<Foo>(s => s
.Query(q => q
.Bool(b => b.Filter(distanceFilters))
)
.Source(src => src
.Includes(i => i
.Fields(
f => f.Field1,
f => f.Field2,
f => f.Field3
)
)
)
.From(options.From)
.Size(options.Size)
);
var hitsMD = searchResponse.HitsMetadata;
var results = hitsMD?.Hits.Select(s => new Hit()
{
Index = s.Index,
Id = s.Id,
Score = s.Score,
Job = s.Source
}
).ToPagedList(PageNumber, PageSize);
Issue
When I call .ToPagedList on the search results returned by ElasticSearch, it only shows one page of results.
The issue is that ElasticSearch has its own paging mechanism so it's only returning one page of hits.
I had the idea that because ElasticSearch passes back the total number of hits I could tell the PagedList how many items are in the list by setting the PagedList.TotalItemCount property. However, I can't do this as it's a private set.
I've tried removing the from and size but this returns 10 hits which is ElasticSearch's default size which they obviously put in place for performance reasons.
Question
How can I make use of the X.PagedList package whilst integrating into ElasticSearch using the Nest API?
You've basically got all the pieces here already. All you're missing is StaticPagedList<T>. Since paging is already being handled by Elasticsearch, you need to simply define a static paging setup, i.e.:
var pagedResults = new StaticPagedList<Foo>(results, PageNumber, PageSize, total);

Only return specific fields in elastic search native query Java api

I'm building a native query but I only want to return certain fields, all of which are held within a parent field. I think I am looking for the QueryBuilders or NativeSearchQueryBuilder equivalent of the REST API's _source. Here's a code example:
NativeSearchQueryBuilder sb = new NativeSearchQueryBuilder()
.withIndices("myIndex")
.withTypes("myType")
.withQuery(QueryBuilders.queryStringQuery("parent.field2:Foo*"));
.withFields("parent.field1");
I'd expect this to return a list of only parent.field1 that are associated with objects that have parent.field2 like Foo*. But it returns nothing.
Thanks for any help!
After some research, I found the answer is in NativeSearchQueryBuilder. I was just using an older version of spring-data elastic search, so I could not see this method: withSourceFilter. The way to do this is:
NativeSearchQueryBuilder sb = new NativeSearchQueryBuilder()
.withIndices("myIndex")
.withTypes("myType")
.withQuery(QueryBuilders.queryStringQuery("parent.field2:Foo*"));
.withSourceFilter(new FetchSourceFilter(<String array of includes>, null));
FetchSourceFilter takes 2 arguments, a String[] array of includes and one of excludes. In my example, I'd have an array like new String[]{"parent.field1"} passed to FetchSourceFilter, which in turn is passed to withSourceFilter. The search above will then return (once built and ran) a list of parent.field1 with parent.field2 like Foo*.
The version I upgraded to was spring-data-elasticsearch 2.0.2.

retrieve data with Contains id

Raven DB gave me this message
Method not supported: Contains
for this code :
using (var d = DataLayer.RavenDB.d.OpenSession())
{
foos = d.Query<Foo>().Where(foo => ids.Contains(foo.Id)).Skip(i * 10).Take(10).ToList();
}
how can I retrieve my list foos ?
It looks like you are trying to query multiple documents by id. Querying by Id is not recommended in Raven. Load them instead. There is an overload that takes multiple Ids.
foos = session.Load<Foo>(ids);
If this was some other property rather than Id, you would use item.In(list) rather than list.Contains(item).
if you want to load the documents based on the list of ids, go the solution suggested by Matt, performance wise Load() is the best approach.
but if you still wants to get it using Query (using some where contiions) change the code like this
using (var d = DataLayer.RavenDB.d.OpenSession())
{
foos = d.Query<Foo>()
.Where(foo => foo.Id.In<string>(ids))
.Skip(i * 10)
.Take(10).ToList();
}

Translate odata uri to expression

I'd like to use an action filter to translate an Odata uri to a Linq expression. I'm doing this because i'm using the resulting expression to query nonSQL line of business systems. In the WCF web api this was trivial because the translated query was appended as a property of the the request object, as such:
var query = (EnumerableQuery)request.Properties["queryToCompose"];
That seems to have disappeared. Are there any public api's i can use to accomplish this?
I've been trying something similiar.. While not perfect, you can grab the OData expressions directly from the query string and build the LINQ expression manually:
var queryParams = HttpUtility.ParseQueryString( ControllerContext.Request.RequestUri.Query );
var top = queryParams.Get( "$top" );
var skip = queryParams.Get( "$skip" );
var orderby = queryParams.Get( "$orderby" );
And the apply that directly to your IQueryable or whatever you're using for the filtering. Not nearly as useful, but its a start.
So as it turns out the query has changed keys in the request property collection. It also seems that the internal filter that parses the query runs after the custom filters and thus doesn't add the query value. To get the translated query, call the following inside the controller action.
(EnumerableQuery<T>)this.Request.Properties["MS_QueryKey"];
Check out Linq2Rest. It solves this problem.

Resources