Elasticsearch-php: function_score not working?

Created on 3 Mar 2014  路  8Comments  路  Source: elastic/elasticsearch-php

hi folks,

i try to pass a function_score request but it doesn't work.

$json = '{
"query": {
"function_score": {
"functions": [
{
"random_score": {

                   }
                }
             ],
             "boost_mode": "replace",
             "query": {
                "match_all": {}
             }
          }
       }
    }';

    $qry = array(
        'query' => array(
            'function_score' => array(
                'functions' => array(
                    array('random_score' => array())
                ),
                'query' => array(
                    array('match_all' => array())
                )
            )
        )
    );

    $searchParams['body']['query']['function_score']['functions']['random_score'] = array();
    $searchParams['body']['query']['function_score']['query']['match_all'] = array();

    //$searchParams['body'] = $qry;

    $retDoc = $elastic->search($searchParams);

if i pass $query i will get a exception: function_score: malformed query, expected a START_OBJECT while parsing functions but got a FIELD_NAME.

If i pass $json, it works. I'm not sure what i'm doing wrong.

Thanks

Most helpful comment

The problem basically boils down to the function score requiring both arrays and objects. Most places in the ES query DSL it doesn't matter, and everything can be cast to arrays without problem The Function Score requires an array of objects, however, so you need to explicitly make the random_score function a PHP object:

Also, you had an extra array on the match_all which was causing problems.

$randomScore = new \stdClass();
$randomScore->seed = 5;

$qry = array(
    'query' => array(
        'function_score' => array(
            'functions' => array(
                array("random_score" => $randomScore)
            ),
            'query' => array('match_all' => array())
        )
    )
);

$searchParams['body'] = $qry;

$client = new Elasticsearch\Client();
$retDoc = $client->search($searchParams);
print_r($retDoc);
(
    [took] => 0
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 0
            [max_score] => 
            [hits] => Array
                (
                )

        )

)

I agree this is confusing, I'll add a section in the docs about it since the syntax is a little different from the rest of the client. It's a general problem with PHP and JSON.

All 8 comments

object(stdClass)#71 (1) {
["query"]=>
object(stdClass)#72 (1) {
["function_score"]=>
object(stdClass)#73 (3) {
["functions"]=>
array(1) {
[0]=>
object(stdClass)#74 (1) {
["random_score"]=>
object(stdClass)#75 (0) {
}
}
}
["boost_mode"]=>
string(7) "replace"
["query"]=>
object(stdClass)#76 (1) {
["match_all"]=>
object(stdClass)#77 (0) {
}
}
}
}
}

array(1) {
["query"]=>
array(1) {
["function_score"]=>
array(2) {
["functions"]=>
array(1) {
[0]=>
array(1) {
["random_score"]=>
array(0) {
}
}
}
["query"]=>
array(1) {
[0]=>
array(1) {
["match_all"]=>
array(0) {
}
}
}
}
}
}

    $q = json_decode($json);

    echo var_dump($q) . '<br>';

    echo var_dump($qry);

The problem basically boils down to the function score requiring both arrays and objects. Most places in the ES query DSL it doesn't matter, and everything can be cast to arrays without problem The Function Score requires an array of objects, however, so you need to explicitly make the random_score function a PHP object:

Also, you had an extra array on the match_all which was causing problems.

$randomScore = new \stdClass();
$randomScore->seed = 5;

$qry = array(
    'query' => array(
        'function_score' => array(
            'functions' => array(
                array("random_score" => $randomScore)
            ),
            'query' => array('match_all' => array())
        )
    )
);

$searchParams['body'] = $qry;

$client = new Elasticsearch\Client();
$retDoc = $client->search($searchParams);
print_r($retDoc);
(
    [took] => 0
    [timed_out] => 
    [_shards] => Array
        (
            [total] => 5
            [successful] => 5
            [failed] => 0
        )

    [hits] => Array
        (
            [total] => 0
            [max_score] => 
            [hits] => Array
                (
                )

        )

)

I agree this is confusing, I'll add a section in the docs about it since the syntax is a little different from the rest of the client. It's a general problem with PHP and JSON.

Thanks for the fast replay. You saved my night!

Glad to help! Going to close this ticket, feel free to reopen (or create a new one) if you have more problems :)

I'm sorry i still have trouble. I'm not able to run this query with php i tried use array and stdClass.

POST /cooking/_search
{
   "from": 0,
   "size": 1,
   "query": {
      "function_score": {
         "functions": [
            {
               "random_score": {}
            }
         ],
         "boost_mode": "replace",
         "query": {
            "bool": {
               "must": [
                  {
                     "term": {
                        "searchTags": "david"
                     }
                  },
                  {
                     "term": {
                        "searchTags": "natalie"
                     }
                  },
                  {
                     "term": {
                        "searchTags": "deutsch"
                     }
                  }
               ],
               "minimum_should_match": 1,
               "boost": 1
            }
         }
      }
   }
}

Try this:

$randomScore = new \stdClass();

$qry = array(
    'from' => 0,
    'size' => 1,
    'query' => array(
        'function_score' => array(
            'functions' => array(
                array("random_score" => $randomScore)
            ),
            'boost_mode' => 'replace',
            'query' => array(
                'bool' => array(
                    'must' => array(
                        array(
                            'term' => array(
                                'searchTags' => 'david'
                            )
                        ),
                        array(
                            'term' => array(
                                'searchTags' => 'natalie'
                            )
                        ),
                        array(
                            'term' => array(
                                'searchTags' => 'natalie'
                            )
                        )
                    ),
                    'minimum_should_match' => 1,
                    'boost' => 1
                )
            )
        )
    )
);

$searchParams['body'] = $qry;

ok i got it! but if you try to assign this request as raw json it won't work. Still like elasticsearch but dynamic and complex requests are hard to code with php :p

Not sure I understand...it works on my end if you pass the raw string as JSON?

In general, the difficulty with creating queries algorithmically (in PHP) boils down to this: "random_score": {}

Any time you need to assign an empty JSON object, you have to specify it with a class. If that random_score had a property (like seed), you can use the array syntax:

'functions' => array(
    array("random_score" => array('seed' => 5))
)

But because it has no properties, you need to use the stdClass syntax:

'functions' => array(
    array("random_score" => new \stdClass())
)

I do agree that PHP's verbosity makes creating queries unpleasant at times :(

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dinamic picture dinamic  路  5Comments

paulhuisman picture paulhuisman  路  6Comments

gustavonecore picture gustavonecore  路  3Comments

opeadeyomoye picture opeadeyomoye  路  4Comments

enumanc picture enumanc  路  5Comments