Multiple criteria within a single SHOULD query block - node.js

I'm hooking into an API which I have no control over and would like to extract all recipe entries which match certain criteria. For the most part, this is a simple 'does value equal N', however for one of these criterion I also have to check if another value is greater than 0.
This code works absolutely fine:
should: [
{ match: { 'ItemResult.ItemAction.Type': 853 } },
{ match: { 'ItemResult.ItemAction.Type': 1013 } },
{ match: { 'ItemResult.ItemAction.Type': 1322 } },
{ match: { 'ItemResult.ItemAction.Type': 5845 } }
]
It gives me all recipe entries whose 'ItemResult.ItemAction.Type is either 853, 1013, 1322 or 5845 as expected. The problem comes with this new more complex condition to my should array:
range: {
'ItemResult.ItemAction.Type': { gte: 5100, lte: 5300 },
'ItemResult.ItemAction.Data0': { gt: 0 }
}, ...
Each individual range property works fine, but naturally I'm getting the following error when both are combined like they are above:
"reason":"[range] query doesn\'t support multiple fields
Is there a way I happily have both ranges considered within the same query without impacting the other ItemResult.ItemAction.Type values?
Obviously I can hook into the API a second time to perform the more complex criterion search, but I'm wondering if I can do it all in the one call.

{
"query": {
"bool": {
"must": [
{
"range": {
"ItemResult.ItemAction.Type": {
"gte": 5100,
"lte": 5300
}
}
},
{
"range": {
"ItemResult.ItemAction.Data0": {
"gt": 0
}
}
}
]
}
}
}
Range from elasticsearch doesn't support multiple fields but you can use this query for having multiple range conditions.

Related

Considering multiple fields when searching in Elasticsearch

I want to implement a simple search query using Elasticsearch.
I have two fields, "title" and "description" that I would like to match the searched term with. Currently, I have the body shown below as the body for search body. How can I make it so that the search prioritizes the title match, but if there are matches in the description, they are still included in the search (with lower priority)? Thanks in advance.
body = {
size: 200,
from: 0,
query: {
prefix: {
title: searchTerm
}
}
}
You have to use a constant score query with a score of 0 for the "other" field. Any other boost / function score usage will not reliably score a certain field over another field as the scoring is based on other parameters like text length for example, this means a constant boost (unless very very large) can not guarantee the behaviour you seek.
By using a constant score for each field you can control score manually, like so:
{
size: 200,
from: 0,
query: {
bool: {
should: [
{
prefix: {
title: searchTerm
}
},
{
constant_score: {
filter: {
prefix: {
description: searchTerm
}
},
boost: 0
}
},
]
}
}
}
If you set description boost to be more than 0 then the score will be the combined score of both fields, by doing this you can prioritize documents that have that prefix in both fields over ones that have it in just the title field.
You can use a combination of bool/should clause along with the boost parameter
{
"query": {
"bool": {
"should": [
{
"prefix": {
"title": {
"value": "searchterm"
}
}
},
{
"prefix": {
"description": {
"value": "searchterm",
"boost": 4
}
}
}
]
}
}
}

Couchdb 2 _find query not using index

I'm struggling with something that should be easy but it's making no sense to me, I have these 2 documents in a database:
{ "name": "foo", "type": "typeA" },
{ "name": "bar", "type": "typeB" }
And I'm posting this to _find:
{
"selector": {
"type": "typeA"
},
"sort": ["name"]
}
Which works as expected but I get a warning that there's no matching index, so I've tried posting various combinations of the following to _index which makes no difference:
{
"index": {
"fields": ["type"]
}
}
{
"index": {
"fields": ["name"]
}
}
{
"index": {
"fields": ["name", "type"]
}
}
If I remove the sort by name and only index the type it works fine except it's not sorted, is this a limitation with couchdbs' mango implementation or am I missing something?
Using a view and map function works fine but I'm curious what mango is/isn't doing here.
With just the type index, I think it will normally be almost as efficient unless you have many documents of each type (as it has to do the sorting stage in memory.)
But since fields are ordered, it would be necessary to do:
{
"index": {
"fields": ["type", "name"]
}
}
to have a contiguous slice of this index for each type that is already ordered by name. But the query planner may not determine that this index applies.
As an example, the current pouchdb-find (which should be similar) needs the more complicated but equivalent query:
{
selector: {type: 'typeA', name: {$gte: null} },
sort: ['type','name']
}
to choose this index and build a plan that doesn't resort to building in memory for any step.

Elasticsearch - MissingMethodException on running distanceInKm on geo_point array

I have an elasticsearch document which has an array of geo_points. I have created the mapping as:
{
"test": {
"properties": {
"locations": {
"type": "geo_point"
}
}
}
}
Now, I am trying to create a query in which I want to do some processing on the array of geo_points. I have created my query like this:
{
"query": {
"filtered": {
"filter": {
"script": {
"script": "sDistance = doc['locations'].values[0].distanceInKm(28.51818,77.096080);"
}
}
}
}
}
I want to calculate the distance of the point (28.51818,77.096080) from the first element in the locations array.
It is giving me this error:
GroovyScriptExecutionException[MissingMethodException[No signature of method: org.elasticsearch.common.geo.GeoPoint.distanceInKm() is applicable for argument types: (java.lang.Double, java.lang.Double) values: [28.51818, 77.09608]]
I tried using sDistance = doc['locations'][0].distanceInKm(28.51818,77.096080); but it also resulted in the same error.
What am I doing wrong here?
Thanks in advance.
Your script should not retrieve the first geo point by itself, but simply call distanceInKm on the locations field directly, like this:
{
"query": {
"filtered": {
"filter": {
"script": {
"script": "sDistance = doc['locations'].distanceInKm(28.51818,77.096080);"
}
}
}
}
}
Under the hood, the first geo point will be retrieved and the distance will be computed on it.

How find all documents in elasticsearch that matches with fields and values?

I have an index users with user type. Mapping is dynamic. For now user hs a following structure:
"user": {
"nested": {
"one":51
},
"other": {
"two":"hi!"
},
"three":false
}
I need to find all users which has other.two field with value hi or has three field with value false. E.g. user which has other.two must have hi value in it or three field with value false. How to select this from elastic search?
I have tried:
GET /users/user/_search
{"query": {"match": {"other.two": "hi"}}}
Returns a user for me, but
GET /users/user/_search
{"query": {"match": {"other.two": "hi", "three":false}}}
Returns me a SearchPhaseExecutionException.
How combine several fields and values for searching?
Use a Bool filter or Bool Query
As #rvheddeg suggested above, here is the query that works for me:
{
"query": {
"bool": {
"should": [
{ "match": { "other.two": "hi" }},
{ "match": { "three": false }}
],
"minimum_should_match": 1
}
}
}

Query the number of elements matching a filter using elastic.js?

I'm building a leaderboard with elasticsearch. I'd like to query all documents who have points greater than a given amount using the following query:
{
"constant_score" : {
"filter" : {
"range" : {
"totalPoints" : {
"gt": 242
}
}
}
}
This works perfectly -- elasticsearch appropriately returns all documents with points greater than 242. However, all I really need is the count of elements matching this query. Since I'm sending the result over the network, it would be helpful if the query simply returned the count, as opposed to all of the documents matching the filter.
How do I get elasticsearch to only report the count of documents matching the filter?
EDIT: I've learned that what I'm looking for is setting search_type to count. However, I'm not sure how to do this with elastic.js. Any noders willing to pitch in their advice?
You can use the query type count for exactly that purpose:
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-search-type.html#count
This is an example that should help you:
GET /mymusic/itunes/_search?search_type=count
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"range": {
"year": {
"gt": 2000
}
}
}
}
}
}

Resources