I have a query that works probably to search across all fields for phrases separated by spaces with partial matching below. In addition, the scoring works as expected where 'Joh' has a lower score then "John' or 'John Do' has a lower score then "John Doe'
POST /user/_search
{
"query": {
"match": {
"_all": {
"query": "John Doe",
"operator": "or",
"fuzziness": 2,
"prefix_length": 1
}
}
}
}
I am now trying to add a layer on top of this query where it returns the results above where the 'state' field MUST be 'California'. My implementation below returns the desired results but now the scoring has the name score when a match is found. For Example 'Joh' where state = 'California' returns the same score as 'John Doe' where state = 'California'. Why is the scoring no longer working properly? Any solution would be greatly appreciated.
GET /user/_search
{
"query": {
"filtered": {
"query": {
"match": {
"_all": {
"query": "John Doe",
"operator": "or"
},
"filter": {
"bool": {
"must": [
{
"term": {
"state": "California"
}
}
]
}
}
}
}
}
}
}
since you are applying filter, the score will be same for all documents.
https://www.elastic.co/guide/en/elasticsearch/guide/current/function-score-filters.html#_filter_versus_query
Probably you can try using Function Score query
Related
This the query I used in elastic search to filter records that either satisfy one condition or does not satisfy other condition.
{
"query":
{
"query_string":
{
"query": "(NOT col1: \"val1\") OR (col2: val2)",
"analyze_wildcard": true
}}}
The problem is I am not able to write an equivalent syntax in nodejs to extract the information. We cant use must_not here as it is an OR condition
You will make both conditions in should array, as, if anyone matches you will get the record in results, you will have to use must match and must_not match
{
"query": {
"bool": {
"should": [
{
"bool": {
"must_not": {
"match": {
"col1": {
"query": "val1",
"type": "phrase"
}
}
}
}
},
{
"match": {
"col2": {
"query": "val2",
"type": "phrase"
}
}
}
]
}
}
}
This is my DSL:
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "testa",
"analyzer":"standard",
"type": "best_fields",
"fields": [ "name^5", "content^1" ]
}
},
"field_value_factor": {
"field": "popular",
"modifier": "log1p",
"factor": 0.1
},
"boost_mode": "sum",
"max_boost": 1.5
}
}
}
When I search a keyword like 'testa',the result only contains the keyword 'testa',What should I do to make the results contains keywords 'testa' and 'test' or 'tes'?
Thank you.
You can use ngram for partial words search, but you need to reindex your documents.
You can check the official example
You may use Fuzzy Match Query where your query will be like:
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "testa",
"analyzer":"standard",
"fuzziness":"3",
"type": "best_fields",
"fields": [ "name^5", "content^1" ]
}
},
"field_value_factor": {
"field": "popular",
"modifier": "log1p",
"factor": 0.1
},
"boost_mode": "sum",
"max_boost": 1.5
}
}
}
Also, Simple Query String Query might help but you will have to enter your term as "tes*", which may or may not be acceptable to your use case.
I am currently trying to do a multi search query on first name, last name, and date of birth. I want the results to show a complete match for first, last, and dob but also show results if the first name and last name match but a different date of birth exists then what was queried on.
As of right now my code only returns a result if all three fields have exact matches
GET /account/data/_search
{
"query": {
"match": {
"first": {
"query": "Chris"
}
}
},
"query": {
"match": {
"last": {
"query": "Johnson"
}
}
},
"query": {
"match": {
"dob": {
"query": "10-10-1990"
}
}
}
}
This can be solved with simple bool query
{
"query": {
"bool": {
"must": [
{
"match": {
"first": "TEXT"
}
},
{
"match": {
"last": "TEXT"
}
}
],
"should": [
{
"match": {
"dob": "TEXT"
}
}
]
}
}
}
I am Querying for getting aggregate data based on date_range, like below
"aggs": {
"range": {
"date_range": {
"field": "sold",
"ranges": [
{ "from": "2014-11-01", "to": "2014-11-30" },
{ "from": "2014-08-01", "to": "2014-08-31" }
]
}
}
}
using this I am getting this response
"aggregations": {
"range": {
"buckets": [
{
"key": "2014-08-01T00:00:00.000Z-2014-08-31T00:00:00.000Z",
"from": 1406851200000,
"from_as_string": "2014-08-01T00:00:00.000Z",
"to": 1409443200000,
"to_as_string": "2014-08-31T00:00:00.000Z",
"doc_count": 1
},
{
"key": "2014-11-01T00:00:00.000Z-2014-11-30T00:00:00.000Z",
"from": 1414800000000,
"from_as_string": "2014-11-01T00:00:00.000Z",
"to": 1417305600000,
"to_as_string": "2014-11-30T00:00:00.000Z",
"doc_count": 2
}
]
}
}
but instead of only doc_count, I have also required complete aggregate data that satisfy this range,
is threre any way to get this..please help
It's not clear what other fields you're looking for so I've included a couple of examples.
By nesting another aggs inside your first one, you can ask Elasticsearch to pull back additional values e.g. averages, sums, counts, min, max, stats, etc.
this example query will bring back field_count - a count of instances of myfield
and also return order_count - a sum based on a script.
"aggs": {
"range": {
"date_range": {
"field": "sold",
"ranges": [
{ "from": "2014-11-01", "to": "2014-11-30" },
{ "from": "2014-08-01", "to": "2014-08-31" }
]
}
}
},
"aggs" : {
"field_count": {"value_count" : { "field" : "myfield" } },
"order_count": {"sum" : {"script" : " doc[\"output_msgtype\"].value == \"order\" ? 1 : 0"} } }}
}
If you aren't looking for any sums, counts, averages on your data - then an aggregation isn't going to help.
I would instead run a standard query once per range. e.g.:
curl -XGET 'http://localhost:9200/test/cars/_search?pretty' -d '{
"fields" : ["price", "color", "make", "sold" ],
"query":{
"filtered": {
"query": {
"match_all" : { }
},
"filter" : {
"range": {"sold": {"gte": "2014-09-21T20:03:12.963","lte": "2014-09-24T20:03:12.963"}}}
}
}
}'
repeat this query as needed but modifying the range each time.
I have an index of documents that look this:
{
url: "/foo/bar",
html_blocks: [
"<h1>hi</h1>"
],
tags: [
"video",
"text"
],
title: "My title"
}
I'd like to query these documents on the title and html_blocks fields, and for any matches add a boost if they have a video tag.
So far, my query looks like this:
{
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
}
}
How do I modify it so that it continues to only return results if a match is found in the existing query, but a boost is added to any of the results which have a video tag? Thanks!
You want a custom_filters_score which will just boost on matches. Note that filter input is not analyzed, so you might wrap that in a query if you need it analyzed. Your other options to boost, while not really for this case are the boosting query, which is good for demoting results and the custom_score_query which is good for added boosts based on some calculated value.
See: Custom_filters_score
{
"query": {
"custom_filters_score": {
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
},
"filters": [
{
"filter": {
"term": {
"tags": "video"
}
},
"boost": 3
}
]
}
}
}
Edit:
This is what I mean by wrapping in a query using a filter query. Trust me, once you get the hang of ES, you'll be nested so knee deep that you'll produce some of the most satisfying queries ever.
{
"query": {
"custom_filters_score": {
"query": {
"query_string": {
"query": "foo",
"fields": [
"title",
"html_blocks"
]
}
},
"filters": [
{
"filter": {
//here comes the filter query, and I changed term to match
//since match analyzes
"query":{
"match": {
"tags": "video"
}
}
},
"boost": 3
}
]
}
}
}