Elasticsearch NEST - SortAsceding doesn't sorts documents - sorting

I am trying to sort the result set based on a field name. But Sort doesn't works with string type.
Tried Code:-
public class Company
{
public long Number { get; set; }
public string Name{ get; set; }
}
My problem is : Sorting is not done when I use SortAscending API, like below
var resultSet = client.Search<Article>(s => s
.Type("Company")
.From(0)
.Size(200)
.QueryString("Stack OverFlow")
.SortAscending(f => f.Name));
Note: Documents are listed as Sorted if I set field name as Number(f => f.Number)
Please help

Your issue with sorting on the name field in your index is probably related to the fact that the field is being analyzed/tokenized. From the Elasticsearch Sort Guide:
For string based types, the field sorted on should not be analyzed / tokenized.
Therefore, you need to provide an additional field that is not analyzed/tokenized to perform your sort against. You can accomplish this by adding an additional field to your documents and setting the mapping for that type/field to not_analyzed or you can leverage multi_field (now just fields in version 1.x) on your existing name field. Please refer to the following for guidance on how to accomplish either of these options:
Multi-Fields (or Fields in v1.X)
Mapping

Related

Problem indexing LongField from custom FieldBridge

for a search using lucene, I made a bridge,
public class EntityIDFieldBridge implements FieldBridge {
#Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
BaseEntity baseEntity = (BaseEntity) value;
if(value !=null){
Field field = new LongField(name, baseEntity.getId(),Field.Store.NO);
document.add(field);
}
}
}
when I search for the value, I dont get the correct documents. when I search term:* I do get the ones that are not null, so I see that its getting indexed.... StringField is working fine. But I think it should be a long field. Any ideas?
Based on the little information you provided, I am assuming that you are not trying to get a value whihc is null.
Field Bridge provided more information on what it is, what lucene supports and how it works:
In Lucene all index fields have to be represented as Strings. For this
reason all entity properties annotated with #Field have to be indexed
in a String form. For most of your properties, Hibernate Search does
the translation job for you thanks to a built-in set of bridges. In
some cases, though you need a more fine grain control over the
translation process.
Also for Null values
null elements are not indexed. Lucene does not support null elements
and this does not make much sense either.

How to index a document using Elasticsearch NEST dynamically?

I want to put documents from different customers to different indexes in Elasticsearch.
Documents have some common part in structure and a part that vary from customer to customer named Data.
C#
class Entity
{
public Guid CustomerId { get; set; }
public IDictionary<string, object> Data { get; set; }
}
JSON
{
"customerId": "10000000-0000-0000-0000-000000000000",
"data": {......}
}
Say we have 10000 "customers" with a million of documents for each. "Customers" may be created and deleted dynamically.
Is it good idea to put documents from different customers to different indexes in Elasticsearch?
Is it possible to create a new index in Elasticsearch based on customerId field of inserted document dynamically? How to do it using .Net client?
I'm looking for something like:
var index = entity.CustomerId;
client.CreateDocument<Entity>(entity, index);
PS I'm using Elasticsearch v7.6
Well, I found an answer. Anyway would be nice if someone comment it how is it good strategically.
Here we go:
var indexName = entity.CustomerId.ToString();
var request = new IndexRequest<Entity>(entity, indexName);
client.Index<Entity>(entity);

How to not index nested collection but still store in Elasticsearch using NEST?

Is there a way in NEST to skip a nested collection or type from being indexed, but still include with the document?
I can use below to completely skip the property, not just from being indexed:
[ElasticProperty(OptOut=true)]
public List<MyClass> subtype { get; set; }
Using Index=FieldIndexOption.no appears to have no effect (the mapping looks the same):
[ElasticProperty(Index=FieldIndexOption.no)]
public List<MyClass> subtype { get; set; }
I want to avoid specify the FieldIndexOption.no on each property of the nest type. Is there a another way?
Edit 1:
Code for creating the index:
elasticClient.CreateIndex("MyParentClass", new IndexSettings());
elasticClient.MapFromAttributes<MyParentClass>();
We're currently on version 0.12 of NEST (upgrade pending).

OData $orderby clause on collection property

I have the following classes :
public class Parent
{
public string ParentProp { get; set; }
public IEnumerable<Child> ManyChildren { get; set; }
}
public class Child
{
public string ChildName { get; set; }
public int Value { get; set; }
}
Say I have an OData operation defined which returns IEnumberable<Parent>. Can I write an $orderby clause which performs the following operation ('parents' is an IEnumerable<Parent>) :
parents.OrderBy(x => x.ManyChildren.Single(y => y.ChildName == "Child1").Value);
I know I can write custom actions (http://msdn.microsoft.com/en-us/library/hh859851(v=vs.103).aspx) to do this ordering for me, but I'd rather use an $orderby clause.
(The only SO question which asked something similar is a little dated - How can I order objects according to some attribute of the child in OData?)
As I tried is possible with nesting $orderby in $expand so will be:
odata/User?&$select=Active,Description,Name,UserId&$expand=Company($select=Active,Name,CreatedBy,CompanyId;$orderby=Active asc)
And what you get is somthing like:
ORDER BY [Project2].[UserId] ASC, [Project2].[C19] ASC
will order a company collection for each user separately.
I think in version OData Client for .NET 6.7.0 is supported, in release notes is writhing:
In query options
$id, $select, $expand(including nested query options)....
I see in version 6.1 that values for nested options exist and is in:
DataQueryOptions->SelectExpand->SelectExpandClasue->SelectedItems->ExpandNavigationItem->OrderByOption
but is not working.
I tried and with System.Web.OData 5.6 and all releated dependencies but seams is not working.
My conclusion:
Seams that is everiting prepared like DataQueryOptions exist nested orderby but is not working.
Like I find out standard seams is going in that direction.
https://issues.oasis-open.org/browse/ODATA-32
It depends on your OData service implementation. Which kind of service are you using? WCFDS, WebAPI, or the service you implement yourself?
Url parser do can parse the URL such as root/People?$orderby=Company/Name. The translator is implemented by service.
And I agree with the answer in related question: "it's not possible to do this with a navigation property that has a cardinality of many". Since it's has a cardinality of many, service cannot know which one should be used to sorting.

Linq dynamic queries for user search screens

I have a database that has a user search screen that is "dynamic" in that I can add additional search criteria on the fly based on what columns are available in the particular view the search is based on and it will allow the user to use them immediately. Previously I had been using nettiers for this database, but now I am programming a new application against it using RIA and EntFramework 4 and LINQ.
I currently have 2 tables that are used for this, one that fills the combobox with the available search string patterns:
LastName
LastName, FirstName
Phone
etc....
then I have an other table that splits those criteria out and is used in my nettiers algorithms. It works well, but I want to use LINQ..and it doesnt fit this model very well. Besides I think I can pare it down to just one table with linq...
using a format similar to this or something very close...
ID Criteria WhereClause
1 LastName 'Lastname Like '%{0}%'
now I know this wont fit specifically into a linq query..but I am trying to use a univeral syntax for clarity here...
the real where clause would look something like this: a=>a.LastName.Contains("{0}")
My first question is: Is that even possible to do? Feed a lambda in to a string and use it in a Linq Query?
My second question is: at one point when I was researching this before I found a linq syntax that had a prefix like it.LastName{0}
and I appear to have tried using it because vestiges of it are still in my test databases...but I dont know recall where I read about it.
Is anyone doing this? I have done some searches and found similar occurances but they mostly have static fields that are optional, not exactly the way I am doing it...
As for your first question, you can do this using Dynamic Linq as described by Scott Gu here
var query = Northwind.Products.Where("Lastname LIKE "test%");
I'm not sure how detailed your dynamic query needs to be, but when I need to do dynamic queries, I create a class to represent filter values. Then I pass that class to a search method on my repository. If the value for a field is null then the query ignores it. If it has a value it adds the appropriate filter.
public class CustomerSearchCriteria{
public string LastName { get; set; }
public string FirstName { get; set; }
public string PhoneName { get; set; }
}
public IEnumberable<Customer> Search(CustomerSearchCriteria criteria){
var q = db.Customers();
if(criteria.FirstName != null){
q = q.Where(c=>c.FirstName.Contains(criteria.FirstName));
}
if(criteria.LastName!= null){
q = q.Where(c=>c.LastName.Contains(criteria.LastName));
}
if(criteria.Phone!= null){
q = q.Where(c=>c.Phone.Contains(criteria.Phone));
}
return q.AsEnumerable();
}

Resources