Elasticsearch Autocomplete Issues - nest

I am trying to create an Autocompletion using Elasticsearch.net, but i keep getting an Invalid response.
But cant figure out why?
My Request looks like this
var descriptor = new SearchDescriptor<EmployeeDocument>()
.Index("employees").Type("employee").From(page - 1).Size(pageSize)
.Suggest(
s => s.Completion(
"my-completion-suggest",
c => c
.Field(f1 => f1.Description)
.Field(f1 => f1.empfirstname)
.Contexts(
queriesDescriptor => queriesDescriptor.Context(
"query-descriptor",
queryDescriptor => queryDescriptor.Prefix(true).Context(query)))));
var response3 = await this.client.SearchAsync<EmployeeDocument>(descriptor);
the error i am getting is
Invalid NEST response built from a unsuccessful low level call on POST: /employees/employee/_search
Audit trail of this API call:
- [1] BadResponse: Node: http://192.168.2.29:9200/ Took: 00:00:00.3543244
ServerError: ServerError: 400Type: search_phase_execution_exception Reason: "all shards failed"
This is how i am calling the method
var results1 = await service.SearchAsync("brenda", page, pageSize);
var results8 = await service.SearchAsync("something else", page, pageSize);
My model is also very straightforward. I left out some properties
[ElasticsearchType(Name = "employee")]
public class EmployeeDocument
{
//[Text(Name = "pkempid")]
public long pkempid { get; set; }
//[Text(Name = "empfirstname")]
public string empfirstname { get; set; }
}

Description and empfirstname need to be mapped as completion field data types. The CompletionField type in NEST can be used for the property type, which will be mapped as a completion data type through automapping.
Additionally, a completion suggester can only specify one field, so chaining multiple calls to .Field() will not work as expected (the last call will be the field used). You can however specify multiple suggesters in one request targeting different fields. It's more usual though, rather than having multiple completion fields in a mapping, to specify multiple input values to a single completion field.
The use case for the completion suggester is to provide fast "search as you type" autocompletion functionality, trading off the power of more complex analysis chains that can be performed with text field data types.

Ok, so I figured out how to do autocomplete, I ended up using Edge NGram Tokenizer First thing I needed to do was setup my indexes with the correct filters.
var response = this.client.CreateIndex(
ElasticConfig.IndexName,
index => index.Mappings(
ms => ms.Map<EmployeeDocument>(
m => m.Properties(
p => p
.Text(t => t.Name(n => n.EmpFirstName).Analyzer("auto-complete").Fields(ff => ff.Keyword(k => k.Name("keyword"))))
.Text(t => t.Name(n => n.pkEmpID).Analyzer("auto-complete-id").Fields(ff => ff.Keyword(k => k.Name("keyword"))))
.Text(t => t.Name(n => n.Description).Analyzer("auto-complete").Fields(ff => ff.Keyword(k => k.Name("keyword")))))))
.Settings(f => f.Analysis(
analysis => analysis
.Analyzers(
analyzers => analyzers
.Custom("auto-complete", a => a.Tokenizer("standard").Filters("lowercase", "auto-complete-filter"))
.Custom("auto-complete-id", a => a.Tokenizer("standard").Filters("lowercase", "auto-complete-id-filter")))
.TokenFilters(tokenFilter => tokenFilter
.EdgeNGram("auto-complete-filter", t => t.MinGram(3).MaxGram(5))
.EdgeNGram("auto-complete-id-filter", t => t.MinGram(1).MaxGram(5))))));
Then for the actual search
var response = await this.client.SearchAsync<EmployeeDocument>(
x => x.Index("default-index").Type("employee").From(page - 1).Size(pageSize)
.Query(q => q
.MultiMatch(m => m
.Query(query)
.Fields(f => f
.Field(_ => _.EmpFirstName)
.Field(_ => _.pkEmpID)
.Field(_ => _.Description))))
.Highlight(
h => h.PreTags("<mark>").PostTags("</mark>").Fields(
f => f.Field(p => p.EmpFirstName),
f => f.Field(p => p.pkEmpID),
f => f.Field(p => p.Description))));

Related

Laravel 8 uploading two images seperately. added same image names in database

This is the controller code:
$player1QID = time().'.'.$request->player1_Id->extension();
$images1= $request->player1_Id->move(public_path('images'), $player1QID);
$player2QID = time().'.'.$request->player2_Id->extension();
$images2= $request->player2_Id->move(public_path('images'), $player2QID);
///this is adding to database:
$registeredusers = Registrations::create([
'tournament_id' => $request->input('tournament_id'),
'player1_name' => $request->input('player1_name'),
'player1_email' => $request->input('player1_email'),
'player1_Id' => $player1QID,
'player1_gender' => $request->player1_gender,
'player1_phone' => $request->input('player1_phone'),
'player2_name' => $request->input('player2_name'),
'player2_email' => $request->input('player2_email'),
'player2_Id' => $player2QID,
'player2_gender' => $request->player2_gender,
'player2_phone' => $request->input('player2_phone'),
'category' => $request->category,
'status' => $request->input('status'),
]);
This is in view blade:
Upload image1
Upload image2
Really appreciate if someone can help
you should first look at your inspection in Chrome, Firefox or whatever you are using, and check what your request contains, I mean if you are sending the images in separate names like:
...
player1_Id:
player2_Id:
...
i think, of course is sending like that because you are receiving it on your controller. Then try save it with datetime at end of name like:
public function obtainImage(Request $request){
$image1=request('player1_Id');
$this->manageImage($image1);
$image2=request('player2_Id');
$this->manageImage($image2);
}
public function manageImage($image){
$fileImageNameExtencion=$image->getClientOriginalName();
$fileName=pathInfo($fileImageNameExtencion, PATHINFO_FILENAME);
$fileExtencion=$image->getClientOriginalExtension();
$newFileName=$fileName."_".time().".".$fileExtencion;
$saveAs=$image->storeAs('public/images',$newFileName);
return $newFileName;
}
where $ newFileName is what you need to save to your database
otherwise you can do a dd ($ player1QID. '-'. $ player2QID) before saving to database and comparing names

Unhandled exception. System.InvalidOperationException: The LINQ expression error by JsonConvert.Deserialize()

I get an error from this code:
var b = content.FormMasterLists.Where(x => x.FormMasterStatus == "pending");
var c = b.Where(x => JsonConvert.DeserializeObject<ApprovalCCB>(x.FormMasterApprovalCcb).Group.SelectMany(x => x.Department).SelectMany(x => x.ApprovalCCBLevel).SelectMany(x => x.Approver).Where(x => x.ApproverEmail == "christ").Any());
But this code runs successfully:
var b = content.FormMasterLists.Where(x => x.FormMasterStatus == "pending").ToList();
var c = b.Where(x => JsonConvert.DeserializeObject<ApprovalCCB>(x.FormMasterApprovalCcb).Group.SelectMany(x => x.Department).SelectMany(x => x.ApprovalCCBLevel).SelectMany(x => x.Approver).Where(x => x.ApproverEmail == "christ").Any());
Is there any way to declare .Where without List()?
Is there any way to declare .Where without List()?
No way in such implementation. EF Core cannot convert JsonConvert.DeserializeObject to the SQL and provide needed filtering on the server side.
So you have to materialise objects to IEnumerable and use client side filtering.
Anyway some databases provide filtering based on JSON content but then you have to create appropriate extension function for EF Core.

NHibernate JoinQueryOver returns all subtype entries

I know there are many similar topics but I couldn't find the answer I am searching for.
I have Message with list of Receivers. I am trying to get all messages with state new and receivers of type A. I get all messages having corresponding receivers but with all of their receivers. I only want to get the receivers I am interested in.
Here is what I am trying to use:
var messages = session.QueryOver<MessageDTO>()
.Where(message => message.State == MessageState.New)
.JoinQueryOver<MessageReceiverDTO>(message => message.MessageReceivers)
.Where(receiver => receiver.Type == ReceiverType.A)
.TransformUsing(Transformers.DistinctRootEntity)
.List();
//.Where(message => message.MessageReceivers.Count > 0)
//.ToList();
Would be great to have help with that. I also tried using Select for getting message and receiver out of the query but that didn't work neither.
Try QueryOver with alias:
MessageDTO messageAlias = null;
MessageReceiverDTO receiverAlias = null;
var query =
session.QueryOver<MessageDTO>(() => messageAlias)
.JoinAlias(() => messageAlias.Receivers, () => receiverAlias)
.Where(() => messageAlias.State == MessageState.New)
.And(() => receiverAlias.Type == ReceiverType.A);
I think Transformers.AliasToEntityMap might be useful here. Basically it transforms each row in your resulting query to an IDictionary with keys corresponding to alias names and values corresponding to entities. For example:
MessageDTO message = null;
MessageReceiverDTO receiver = null;
var messages = session.QueryOver<MessageDTO>(() => messageAlias)
.Where(message => message.State == MessageState.New)
.JoinQueryOver<MessageReceiverDTO>(message => message.MessageReceivers, () => receiver)
.Where(receiver => receiver.Type == ReceiverType.A)
.TransformUsing(Transformers.AliasToEntityMap)
.List<IDictionary>();
MessageDTO firstMessage = (MessageDTO)messages[0]["message"];
MessageReceiverDTO firstReceiver = (MessageReceiverDTO)messages[0]["receiver"];

NHibernate QueryOver over many tables

There is an entity Effort that has a property List and a property AdType
We have several adTypes enum objects and specialLists enum objects to select IList<Effort>
I do it in this way:
return NHibernateSession.QueryOver<Effort>()
.JoinQueryOver(effort => effort.AdType)
.WhereRestrictionOn(adType => adType.Id)
.IsIn(adTypes.Select(adt => (long)adt).ToList())
.Clone()
.JoinQueryOver(effort => effort.List)
.WhereRestrictionOn(list => list.Id)
.IsIn(specialLists.Select(sl => (long)sl).ToList())
.List<Effort>();
as u can see I use a strange Clone() method that doesn't have any description. It works great.
In what way do you use QueryOver for such queries?
.JoinQueryOver(effort => effort.AdType) will return a QueryOver with a subtype, here AdType IQueryOver<Effort, Adtype> instead of the original IQueryOver<Effort, Effort>. The first generic argument is the queryType and the second the type on which the methods are operating on. If you clone in between the whole query is copyied and returned as the basequery IQueryOver<Effort, Effort>.
To prevent the QueryOver to switch to the subtype there is JoinAlias which creates an alias instead of descending.
AdType adAlias = null;
ListType listAlias = null;
return NHibernateSession.QueryOver<Effort>()
.JoinAlias(effort => effort.AdType, () => adAlias)
.JoinAlias(effort => effort.List, () => listAlias)
.WhereRestrictionOn(() => adAlias.Id).IsIn(adTypes.Cast<long>().ToList())
.WhereRestrictionOn(() => listAlias.Id).IsIn(specialLists.Cast<long>().ToList())
.List<Effort>();
not that if you only Restrict on the Id of adtype and listtype then
return NHibernateSession.QueryOver<Effort>()
.WhereRestrictionOn(effort => effort.Adtype.Id).IsIn(adTypes.Cast<long>().ToList())
.WhereRestrictionOn(effort => effort.List.Id).IsIn(specialLists.Cast<long>().ToList())
.List<Effort>();

Is this the right way of using ThenFetch() to load multiple collections?

I'm trying to load all the collections eagerly, using NHibernate 3 alpha 1. I'm wondering if this the right way of using ThenFetch()?
Properties with plural names are collections. The others are just a single object.
IQueryable<T> milestoneInstances = Db.Find<T, IQueryable<T>>(db =>
from mi in db
where mi.RunDate == runDate
select mi).Fetch(mi => mi.Milestone)
.ThenFetch(m => m.PrimaryOwners)
.Fetch(mi => mi.Milestone)
.ThenFetch(m => m.SecondaryOwners)
.Fetch(mi => mi.Milestone)
.ThenFetch(m => m.Predecessors)
.Fetch(mi => mi.Milestone)
.ThenFetch(m => m.Function)
.Fetch(mi => mi.Milestone)
.ThenFetchMany(m => m.Jobs)
.ThenFetch(j => j.Source)
;
I thought of asking this in the NHibernate forums but unfortunately access to google groups is forbidden from where I am. I know Fabio is here, so maybe the guys from the NHibernate team can shed some light on this?
Thanks
Apparently, there's no "right" way to use ThenFetch in such a case. Your example works fine but SQL produced contains many joins to Milestone, which isn't that right.
Using IQueryOver instead of IQueryable allows you to use complex syntax in Fetch:
Fetch(p => p.B)
Fetch(p => p.B.C) // if B is not a collection ... or
Fetch(p => p.B[0].C) // if B is a collection ... or
Fetch(p => p.B.First().C) // if B is an IEnumerable (using .First() extension method)
So in your case it would be:
query // = session.QueryOver<X>()
.Fetch(mi => mi.Milestone).Eager
.Fetch(mi => mi.Milestone.PrimaryOwners).Eager
.Fetch(mi => mi.Milestone.SecondaryOwners).Eager
.Fetch(mi => mi.Milestone.Predecessors).Eager
.Fetch(mi => mi.Milestone.Function).Eager
.Fetch(mi => mi.Milestone.Jobs).Eager
.Fetch(mi => mi.Milestone.Jobs.First().Source).Eager
The one thing you are missing is that you should use FetchMany() and ThenFetchMany() is the child property is a collection.
IQueryable<T> milestoneInstances = Db.Find<T, IQueryable<T>>(db =>
from mi in db
where mi.RunDate == runDate
select mi);
var fetch = milestoneInstances.Fetch(f => f.Milestone);
fetch.ThenFetch(f => f.PrimaryOwners);
fetch.ThenFetch(f => f.SecondaryOwners);
//...
As leora said, make sure when fetching children collections that you use
FetchMany()
ThenFetchMany()
A new Fetch, should pick up from the root, but this does not always happen. Sometimes you need to create them as separate queries or use Criteria Futures to batch up a multiple fetch.