Nesting function_score inside a bool query - elasticsearch

I want to combine the result of a function_score with other clauses inside a bool query.
{
'bool': {
'must': [
{
'function_score': {
'query': {
'exists': {
'field': 'field_A',
}
},
'script_score': {
'script': {
'source': "doc['field_A'].value / (doc['field_A'].value + params.pivot)",
'params': {
'pivot': 1000,
}
}
},
},
},
{
'rank_feature': {
'field': 'field_B',
}
}
]
}
}
The score stays the same, whether I include the function_score clause or not.
If I replace script_score with a field_value_factor, it does get reflected in the final score.

Related

How to filter results in graphql?

Let's say I have the following schema:
query Publications($id: ProfileId!) {
publications(
request: { profileId: $id }
) {
items {
typename
}
}
}
And I get a result like so:
{
"data": {
"publications": {
"items": [
{
"typename": "Article"
},
{
"typename": "Post"
},
{
"typename": "Post"
},
]
}
}
}
How do I filter my results so I only get the "typename": "Article"?
One way is to add a second optional parameter to your query:
query Publications($id: ProfileId!, $typename: String) {
publications(
request: { profileId: $id , typename: $typename}
) {
items {
typename
}
}
}
Then in your resolver, if you see that typename has a value, filter your results to match.

Elasticsearch malformed query, expected [END_OBJECT] but found [FIELD_NAME]

I'm using the elasticsearch client for doing some search query using constant_score and aggregations but it's throwing the exception:
[parsing_exception] [constant_score] malformed query, expected [END_OBJECT] but found [FIELD_NAME]
This is where I'm creating the query and calling the search function:
fetchData: function fetchFn(req, res, next) {
var model = new urlModel();
util.log('Fetching data from ES::');
var query = buildAggregateUrl(req.reqData);
// if (req.reqData['domain']) {
// var termFilter = { "term": { "domain": req.reqData.domain } };
// query.constant_score.filter.bool.must.push(termFilter);
// }
model.search({ query }, function (er, re) {
if (re) {
req.sendResult = re;
}
next(er);
});
function buildAggregateUrl(opts) {
var query = {
constant_score: {
filter: {
bool: {
must: [{
"range": {
"timestamp": {
"gte": opts.startTime,
"lte": opts.endTime
}
}
}]
}
}
},
aggs: {
success: {
scripted_metric: {
init_script: "params._agg.succ=0;",
map_script: "if(doc.status.value=='success'){params._agg.succ+=1}",
combine_script: "return params._agg.succ",
reduce_script: "int sum=0;for (a in params._aggs){sum+=a}return sum"
}
},
failure: {
scripted_metric: {
init_script: "params._agg.fail=0;",
map_script: "if(doc.status.value=='failure'){params._agg.fail+=1}",
combine_script: "return params._agg.fail",
reduce_script: "int sum=0;for (a in params._aggs){sum+=a}return sum"
}
}
}
};
return query;
}
}
And this is what the search function looks like:
es_model.prototype.search = function (opts, cb) {
var query = {
index: this.esConfig.index,
type: this.esConfig.type,
body: {query:opts.query}
};
console.log('Query ===> ',query);
this.client.search(query, cb);
}
I can't figure out where the problem is with the syntax.I tried wrapping the constant_score key withtin query as well but it doesn't seem to work.
You're simply missing a query element at the top level:
{
query: {
constant_score: {
filter: {
bool: {
must: [{
"range": {
"timestamp": {
"gte": opts.startTime,
"lte": opts.endTime
}
}
}]
}
}
}
},
aggs: {
success: {
scripted_metric: {
init_script: "params._agg.succ=0;",
map_script: "if(doc.status.value=='success'){params._agg.succ+=1}",
combine_script: "return params._agg.succ",
reduce_script: "int sum=0;for (a in params._aggs){sum+=a}return sum"
}
},
failure: {
scripted_metric: {
init_script: "params._agg.fail=0;",
map_script: "if(doc.status.value=='failure'){params._agg.fail+=1}",
combine_script: "return params._agg.fail",
reduce_script: "int sum=0;for (a in params._aggs){sum+=a}return sum"
}
}
}
}
Also note that your client code should look like this:
es_model.prototype.search = function (opts, cb) {
var query = {
index: this.esConfig.index,
type: this.esConfig.type,
body: opts.query
};
this.client.search(query, cb);
}

Elasticsearch searching and sorting across 2 models

I have 2 models: Products and Skus, where a Product has one or more Skus, and a Sku belongs to exactly one Product. They have the following columns:
Product: id, title, content, category_id
Sku: id, product_id, price
I'd like to be able to display 48 products per page across various search and sort configurations, but I'm having trouble translating this to elasticsearch.
For example, it's not clear to me how I would search on title while sorting the relevant results by the lowest-priced Sku for each Product. I've tried a few different things, and closest has been to index everything as belonging to the Sku, then searching like so:
size: '48',
aggs: {
group_by_product: {
terms: { field: 'product_id' }
}
},
filter: {
and: [{
bool: {
must: { range: { price: { gte: 0, lte: 50 } } }
},{
bool: {
must: { terms: { category_id: [ 1, 2, 3, 4, 5, 6 ] } }
}
}]
},
query: {
fuzzy_like_this: {
fields: [ 'title', 'content' ],
like_text: 'Chair',
fuzziness: 1
}
}
But this gives 48 matching Skus, many of which belong to the same Product, so my pagination is off if I try to combine them after the search.
What would be the best way to handle this use case?
Update
Trying with the nested method, using the following structure:
{
size: '48',
query:
{ bool:
{ should:
{ fuzzy_like_this:
{ fields: [ 'title' ],
like_text: 'chair',
fuzziness: 1 },
},
{ must:
{ nested:
{ path: 'skus',
query:
{ bool:
{ must: { range: { price: { gte: 0, lte: 100 } } }
}
}
}
}
}
}
},
sort:
{ _score: 'asc',
'skus.price':
{ nested_path: 'skus',
nested_filter:
{ range: { 'skus.price': { gte: 0, lte: 100 } } },
order: 'asc',
mode: 'min'
}
}
}
This is likely closer, but still not sure how to format it. The above gives products ordered by price, but seems to completely disregard the search field.
Since paginating aggregation results is not possible, even though the approach of including the sku inside the product is a good one, I would go with nested objects depending on the requirements for queries.
As an example query:
GET /product/test/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": {
"query": "whatever",
"fuzziness": 1,
"prefix_length": 3
}
}
},
{
"nested": {
"path": "skus",
"query": {
"range": {
"skus.price": {
"gte": 11,
"lte": 50
}
}
}
}
}
]
}
},
"sort": [
{
"skus.price": {
"nested_path": "skus",
"order": "asc",
"mode": "min"
}
}
]
}

Ignored boosts on custom filters score query

I'm using the custom filters score query but the boosts declared in the "terms" filters are being ignored. The only score that's not ignored is the "script" one in the "exists" filter. I reviewed the documentation many times in order to find the problem but I had no success.
This is the actual query:
{
'from': 0,
'query': {
'custom_filters_score': {
'filters': [
{
'filter': {
'exists': {
'field': 'tweet_article_poster'
}
},
'script': "doc['actual_rank'].value/5000.0 + 1.0"
},
{
'boost': '1.3',
'filter': {
'terms': {
'entities.text': [
'Google',
'Twitter',
'Obama',
'NFL'
]
}
}
},
{
'boost': '1.3',
'filter': {
'terms': {
'category': [
'Sports',
'Politics',
'Technology_Internet'
]
}
}
},
{
'boost': '2',
'filter': {
'terms': {
'tweet_article_poster': [
'JoeGumby1',
'BBCSport',
'EyeOnNFL',
'MadeOfWWEAndHTC'
]
}
}
}
],
'query': {
'bool': {
'must': {
'range': {
'added': {
'from': '2013-10-27T00:00:00'
}
}
},
'must_not': {
'term': {
'show': 'false'
}
}
}
},
'score_mode': 'multiply'
}
},
'si
ze': 20
}
I would guess that boost is not getting applied because your terms filters don't match anything. It probably happens because the tweet_article_poster, category, and entities.text fields are "analyzed" during indexing and therefore converted to the lower case, while terms filter doesn't perform analysis and tries to find terms as is.

In Elasticsearch how do I boost selected terms while still using a wildcard?

I can't figure out from the documentation how to do a wildcard search across several terms but just boost/de-boost a few.
I have a JSON construct like:
{
'indices_boost': {
'football': 1.2,
'horse-race': 1.1
},
'query': {
'bool': {
'minimum_number_should_match': 2,
'should': [
{
'wildcard': {
'name': {
'boost': 1.2,
'value': 'polan*'
}
}
},
{
'wildcard': {
'nicknames': u
'polan*'
}
},
{
'wildcard': {
'horses': 'polan*'
}
},
{
'wildcard': {
'jockeys': 'polan*'
}
},
{
'wildcard': {
'parent': {
'boost': 0.7,
'value': 'polan*'
}
}
},
{
'terms': {
'minimum_match': 1,
'state': [
'upcoming',
'live'
]
}
}
]
}
},
'size': 5
}
The intent is that a wildcard match on the name field should be boosted, while a wildcard match on the parent field is still relevant but shouldn't be put above results where name is matched.
This particular query doesn't return results even though it should (a query for _all with wildcard returns results).
You can use 'boost':0.0 to eliminate impact of the matched term on the score.
If you have non-default analyzers specified for your fields, these fields might contain terms that are different from the _all field, which might explain why wildcards work for _all but fail for individual fields.

Resources