I'm trying to do a seemingly simple elastic query but im failing and i cannot really find anything on the subject.
I have the following model (lets call it response)
{
string id,
int category,
answers: [{
string answer,
string innerId
int type,
}]
}
some of the answers may not have an actual answer (i.e. the answer field is an empty string).
I have 2 scenarios that i have problems with.
My first case i cannot solve is such that I must find all nested objects that are of type = 1 and have something in the answer field. I came up with this query this option which gives me all the responses that have at least one answer that is of type 1, including the responses that have an empty string for answer, which i want to exclude.
{
"query": {
"nested": {
"path": "surveyResponseAnswers",
"query": {
"bool": {
"must": [
{
"match": {
"surveyResponseAnswers.questionType": 1
}
}
]
}
}
}
}
}
Ive tried adding a
"must_not": [{
"match": {
"surveyResponseAnswers.answer": ""
}
]
On the same level as the must but what i think happens is that it gives me the response parent because there are other answers that have a value in the answer property, about which i dont care.
My second case is such that I must find all nested objects that are of type = 1 and the answer field contains another string/substring, for which i came up with the following query, but this gives me results only for answers that match the full search word i have.
{
"query": {
"nested": {
"path": "answers",
"query": {
"bool": {
"must": [{
"match": {
"answers.type": 1
}
}, {
"match": {
"answers.answer": "text"
}
}]
}
}
}
}
}
For you first problem, try using "constant_score" and then filter. Your query will look like this.
{
"query": {
"nested": {
"path": "surveyResponseAnswers",
"query": {
"bool": {
"must": [
{
"match": {
"surveyResponseAnswers.questionType": 1
}
},
{
"constant_score": {
"filter": {
"exists": {
"field": "surveyResponseAnswers.answer"
}
}
}
}
]
}
}
}
}
}
for, your second problem, try using "term", if you want to search for whole word, or "prefix" , based on what you are required.
For more details, please see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
Related
I have simple Node Js application.
I want get filtered data by Path field, that contains 'get' word.
For example my data is like below:
"_source": {
"time": "2020-03-12T01:25:41.61836-07:00",
"level": "Info",
"info": {
"IpAddress": "0.0.0.0",
"Path": "/api/test/getTest/1",
"QueryString": "",
"UserAgent": "",
"LogDate": "2020-03-12T08:25:41.6220806Z",
"Username": "cavidan.aliyev",
"NodeId": "123456"
}
In other words my entity object's structure like as below:
{
time,
level,
info: {
IpAddress,
Path,
QueryString,
UserAgent,
LogDate,
Username,
NodeId
}
}
My query is like below:
client.search({
index: collectionName,
body: {
from: (params.currentPage - 1) * params.pageSize,
size: params.pageSize,
"query": {
"bool": {
"must": mustArr,
"filter": [
{
"match_all": {}
}
]
}
}
}
}, function (err, res) {
if (err) {
reject(err);
}
else {
let result = res.hits.hits. map(x => x._source);
resolve(result);
}
});
How I can filter data by Path field, that contains 'get' word?
Please help me, thanks
You can make use of Wildcard Query inside the filter query you have. I'm assuming that you are making use of Standard Analyzer for info.Path field.
Note that for the sake of simplicity I've just mentioned what should be going inside the filter query you have.
If info.Path is nested type:
POST <your_index_name>/_search
{
"query": {
"bool": {
"filter": { <--- Note this
"nested": {
"path": "info",
"query": {
"wildcard": {
"info.Path": {
"value": "*get*"
}
}
}
}
}
}
}
}
If info.Path is object type:
POST <your_index_name>/_search
{
"query": {
"bool": {
"filter": { <--- Note this
"wildcard":{
"info.Path": "*get*"
}
}
}
}
}
Important Note: Wildcard search slows the query performance, and if you have a control on the Elasticsearch's index, then you should definitely look at ngram search model, which creates n-gram tokens at index-time as mentioned in this link.
Let me know if this helps!
If you don't want returned data with "get" keywords, your wildcard should type into the must_not.
For example:
POST <your_index_name>/_search
{
"query": {
"bool": {
"must_not":{
"filter": {
"wildcard":{
"info.Path": "*get*"
}
}
}
}
}
}
I have been trying to find out entries which match query 'abc' and from all those entries returned by multi_match i need to filter entries based on entries which contain given business_id where business_id is one of the fields.
i have tried with below query but no records returned from search even though there is one record satisfying both must and filter query.
Problem is in filter query as when i commented it got 2 records returned by multi_match as required and now i want to filter these records based on business_id so finally should get only one record but filter query is not working.
GET customer/_search
{
"query": {
"bool": {
"must": {
"dis_max": {
"queries":
{
"multi_match": {
"query": "abc",
"type": "phrase_prefix",
"fields": ["first_name", "last_name", "email", "city", "state", "zip", "country"]
}
}
}
},
"filter": {
"term": {
"business_id": business_id
}
}
}
}
}
Here is how my records in index looks like
In order to debug this, I suggest that you'll only search with the must section in the query and see that you get the result you expect, and then do the same with only the filter part.
What you want to see is that on both queries you'll get the document you expect. I believe that one of them should not return the document you expect, and then you could try to understand why (and update the question if needed).
If both must and filter return the doc you expect then the above query should work just fine. Also, if that doesn't work, please add the document that you expect to receive back
GET customer/_search
{
"query": {
"bool": {
"must": {
"dis_max": {
"queries":
{
"multi_match": {
"query": "abc",
"type": "phrase_prefix",
"fields": ["first_name", "last_name", "email", "city", "state", "zip", "country"]
}
}
}
},
"filter": {
"match": {
"business_id": business_id
}
}
}
}
}
Solution to my Question . Now filter query is working fine as i have replaced term with match.
I'm trying to get data from elastic search by querying some field which indicates if the object was already handled. let's call it 'isHandled".
There are some objects that indexed without this field.
Is there any way to get the data that "isHandled" is just not "true" (false or even missing)?
Thanks
You can use the exists query to achieve that. This query will return you all documents where isHandled is either false or not existing.
{
"query": {
"bool": {
"should": [
{
"term": {
"isHandled": "false"
}
},
{
"bool": {
"must_not": {
"exists": {
"field": "isHandled"
}
}
}
}
]
}
}
}
I'm very new to ElasticSearch and trying out the parent-child relationship.
My mappings look like this
mappings: {
parent: {
properties: {
sts: {
type: long
}
md: {
type: string
}
dty: {
type: string
}
cid: {
type: string
}
}
}
child: {
_routing: {
required: true
}
_parent: {
type: parent
}
properties: {
cons: {
type: string
}
ccnid: {
type: string
}
nid: {
type: string
}
}
}
}
I created the parents using the bulk API
{"index":{"_id":"cusId:NodeId1"," _routing":"cusId"}}
{"cid":"cusId","sts":0,"nm":"NodeId1_t"}
{"index":{"_id":"cusId:NodeId2"," _routing":"cusId"}}
{"cid":"cusId","sts":0,"nm":"NodeId2_t"}
I created these children
{"index":{"_id":"c4","_routing":"cusId","parent":"cusId:NodeId1"}}
{"cons":["animals","treat","cat","feet"],"ccnid":"cusId","nid":"NodeId1"}
{"index":{"_id":"c5","_routing":"cusId","parent":"cusId:NodeId2"}}
{"cons":["cats","animals","something"],"ccnid":"cusId","nid":"NodeId2"}
Now when I search for has_child in parent; I get nothing.
However, if I change cons to be not an array and just a plain string with the value "animals" in it, the query returns the correct results.
Any ideas would be greatly appreciated.
{
"query": {
"has_child": {
"type": "child",
"query": {
"bool": {
"must": [
{
"term": {
"cons": "animals"
}
}
]
}
}
}
}
}
since you are new to elasticsearch, you need to know how ES analyzes the text you provide.
Since you are using the term query, ES is not going to analyze the text and is going to look for an exact match.
You need to change your child mapping if you want to use term query
like this
"properties": {
"cons": {
"type": "string",
"index" : "not_analyzed"
},
"ccnid": {
"type": "string"
},
"nid": {
"type": "string"
}
}
If I am not wrong, You were using default standard analyzer as you did not specify any analyzers. index : not_analyzed will index the term as it is.
After that below query will give you the expected results. You need to use terms query for multiple match. The query will give you parents which has either "animals" or "treat" inside the array.
GET parent_index/parent/_search
{
"query": {
"has_child": {
"type": "child",
"query": {
"bool": {
"must": [
{
"terms": {
"cons": [
"animals",
"treat"
]
}
}
]
}
}
}
}
}
ES gives lot of ways to query your data, based on what you want
Am new to elastic search, this is my query to find a exact match in my collection.
{
"query": {
"filtered": {
"query": {
"match": {
"_id": {
"query": "1"
}
}
},
"filter": {
"term" : {
"team_id":"2",
"created_user":"099"
}
}
}
}
}
By running this query I am getting one record, but my problem is its not matching "team_id" filed. When I change team_id to some other value eg: 4, I am still getting the record with team_id = 2, Please help me to write an elastic search query with three fields. Thanks
If you want exact match, be sure that fields that you want to make search operation must be not_analyzed. And it seems you are using multiple case in your filter. You can refactor your query by using and filter like;
{
"query": {
"filtered": {
"query": {
"match": {
"_id": {
"query": "1" // remember that, this will always return one result. Update here according to your needs. For example, use tag instead of _id like tag=responsive in order to get results that matches tag field with responsive
}
}
},
"filter": {
"and": [
{
"term": {"team_id":"2"}
},
{
"term": {"created_user":"099"}
}
]
}
}
}