ElasticSearch Nest: Can only use prefix queries on keyword and text fields - not on which is of type float - elasticsearch

Searching values in multiple fields is not working when search text contains space. For example if i search for value "price" than i get results but if i search for "price level" than i get following error:
Can only use prefix queries on keyword and text fields - not on which
is of type float
I have one date field and one float field in indexed documents. And error is thrown because of this fields.
Following is my code of creating Index:
var createIndexResponse = client.CreateIndex("messages", c => c.Settings(s => s.NumberOfShards(1).NumberOfReplicas(0).Analysis(a => a.Analyzers(anl => anl.Custom("default", ca => ca.Tokenizer("whitespace").Filters(new List<string>() { "lowercase" }))))).Mappings(ms => ms.Map<Object>(m => m.Properties(p => p.Number(s => s.Name("id").Index(false)).Text(s => s.Name("displaytext").Index(false)).Text(s => s.Name("text").Index(false)).Text(s => s.Name("url").Index(false)).Date(d => d.Name("Search_ReceivedOn"))))));
Following is my search query:
Dim funcMust = New List(Of Func(Of Nest.QueryContainerDescriptor(Of Object), Nest.QueryContainer))()
funcMust.Add(Function(sh) sh.Term("From", UserID) Or sh.Term("To", UserID))
Dim resp = client.Search(Of Object)(Function(s) s.Index("messages").IgnoreUnavailable(True) _
.Query(Function(qry) qry.QueryString(Function(qs) qs.Fields("Search_*").Query(searchText).DefaultOperator(Nest.Operator.And))) _
.PostFilter(Function(pf) pf.Bool(Function(b) b.Must(funcMust))).From((pageIndex - 1) * pageSize).Take(pageSize).Source(Function(x) x.Includes(Function(f) f.Fields(fields))))
I have dynamic columns in indexed document so i can not use term queries with exact field names. Is there any way to search on all fields that starts with "Search_" without error i have mentioned above?

In my case this occurred when i perform search with spacial character.
I fixed this with following,
Elasticsearch - v6.8.6
Map<String, Float> fields = new HashMap<>();
fields.put("content.keyword", 1f);
fields.put("name.keyword", 2f);
fields.put("tag.keyword", 3f);
SimpleQueryStringBuilder queryBuilder = new SimpleQueryStringBuilder(searchQuery);
queryBuilder.fields(fields);
queryBuilder.analyzeWildcard(Boolean.TRUE);

Related

Elastic search filter using query string

Using Query string OnFieldWithBoosts added different fields need to apply filter, string fields records are working fine.
For id field when I include .Add(id,2) it does not return ID based result.
When I use term then ID fields records working fine.
Now in the query section,
I have used OR condition, so when first condition satisfies, it does not check second one.
If I user AND condition, then it checks for both the condition matches.
But I need first query results and second query results concat into one result
CODE:
var result = client.Search<dynamic>(q => q
.Indices("test")
.Types("user")
.From(1)
.Size(10)
.MinScore(1.0)
.Fields("id", "createddate", "email", "modifieddate", "name", "companyname") // Result set Fields Fields
.Query(q1 =>
{
qq = (q1.ConstantScore(a => a.Filter(b => b.Term("id", searchKeyword))))
|| q1.QueryString(qs => qs.Query(searchKeyword).OnFieldsWithBoost(a => a.Add("notes",3).Add("email", 2).Add("name", 2)));
return qq;
})
);

NEST MultiGet search all types possible?

I have got unique document ids (across all types) and I would like to check which document already exists in elasticsearch index. I try to search
var duplicateCheck = _elasticClient
.MultiGet(m => m.GetMany<object>(notices.Select(s => s.Id)).Fields("Id"));
but it returns wrong result - every document has set found property to false.
update
there is workaround here
var exisitngDocIds = _elasticClient.Search<ZPBase>(s => s
.AllTypes()
.Query(q => q.Ids(notices.Select(z=>z.Id)))
.Fields("Id")
.Take(notices.Count)
);
notices = notices.Where(q => !exisitngDocIds.Hits.Any(s => s.Id == q.Id)).ToList();
From the Multi Get API documentation I realized that you can use something similar to the following code to solve your problem:
var response = _elasticClient.MultiGet(m => m
.Index(MyIndex)
.Type("")
.GetMany<ZPBase>(noticeIds));
Note the empty string passed as the Type.

Delete from elasticsearch all items where field does not match a certan value

I'm trying to delete all items from Elasticsearch index where field time_crawl_started does NOT match a specific value. I'm using match_all query in combination with NOT filter.
This is what I got so far:
$client = new Elasticsearch\Client();
$params = Array(
'index' => ...,
'type' => ...
);
$params['body']['query']['filtered']['query']['match_all'] = Array();
$params['body']['query']['filtered']['filter']['not']['term']['time_crawl_started'] = $someDate;
$client->deleteByQuery($params);
The problem is that this deletes all items, even ones having time_crawl_started set to $someDate, which is simply a datetime such as "2014-02-17 19:13:31".
How should I change this to delete only the items that don't have the correct date?
The problem was that time_crawl_started field was analyzed and thus any comparison by value was wrong. I had to create index manually (as opposed to automagically by just inserting a new document into non-existing index) and specify mapping for my item type, setting 'index' => 'not_analyzed' for time_crawl_started.
And I ended up using script filter like this:
$params['body']['query']['filtered']['query']['match_all'] = Array();
$params['body']['query']['filtered']['filter']['script']['script'] = "doc['time_crawl_started'].value != \"" . $someDate . "\"";

How to get a list of the grouped values in linq groupby?

Linq newbie here, struggling with my first GroupBy query.
I have a list of objects of type KeywordInstance which represents a keyword, and the ID of the database record to which the keyword was applied.
Keyword RecordID
macrophages 1
macrophages 2
cell cycle 3
map kinase 2
cell cycle 1
What I want is a collection of all keywords, with a list of the RecordIDs to which each keyword was applied.
Keyword RecordIDs
macrophages 1, 2
cell cycle 1, 3
map kinase 2
I tried using Linq to get it into a new object. I only managed to get the distinct keywords.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key});
The problem is that I can't seem to get the values of g in any way. g is of the type IGrouping<String, KeywordInstance> and by documentation, it only has the property Key, but not even the property Value. All the examples I have seen on the Internet for groupby just tell me to select g itself, but the result of
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new {keyword = g.Key, RecordIDs = g});
is not what I want.
Any try to get something out of g fails with the error message System.Linq.IGropuing<string, UserQuery.KeywordInstance> does not have a definition for [whatever I tried].
What am I doing wrong here?
I think you are close to you solution.
var keywords = allWords
.GroupBy(w => w.keyword)
.Select(g => new
{
keyword = g.Key,
RecordIDs = g.Select(c => c.ID)
});
Just Select the records you need.
The reason you are seeing the Keyword-column as well as the ID-column, is becuase it's part of g
var keywords = allWords.GroupBy(w => w.keyword);
foreach (var itm in keywords)
{
var list = itm.ToList();
//list returns all of the original properties/values objects from allwords.
//itm.key returns w.keyword
}

Error getting items from Entity Framework using Lambda query

I have a listbox that I am trying to populate with the result of a SQL Server query via a Entity Framework linq/lambda query. I am feeding the query with a value from a combobox. I keep getting lot of errors like the following: Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Any suggestions on how to fix this? I just want two fields to populate in a grid
var pAt = ent.Patterns.Where(p => p.Case_Id == (cbCase.SelectedItem as Case).Case_Id).Select(x => new Pattern{ PatternID = x.PatternID, Pattern1 = x.Pattern1 });
listBox1.DataSource = pAt;
listBox1.ValueMember = "PatternID";
listBox1.DisplayMember = "Pattern1";
Try this instead :
var pAt = ent.Patterns.AsEnumerable()
.Where(p => p.Case_Id == ((Case)cbCase.SelectedItem).Case_Id)
.Select(x => new Pattern{ PatternID = x.PatternID, Pattern1 = x.Pattern1 });
Hope this will fix your issue.
Separate the code parts from the SQL parts. Entity Framework can't necessarily construct an SQL query using code objects, but you can usually work around it. Eg:
var caseId = (cbCase.SelectedItem as Case).Case_Id;
var pAt = ent.Patterns.Where(p => p.Case_Id == caseId)
.ToArray()
.Select(x => new Pattern { PatternID = x.PatternID, Pattern1 = x.Pattern1 });

Resources