Sorting in elastic search based upon user entered values - php

I want to get the products in the order of user input. Suppose if user search
"Z1234","S1234","T2344", then I want products in that particular order. Where Z1234 will be the first record.
How this can be achieved in the elastic search. I have tried using "script" and other ways but it does not work. Below are the example of my script usage.
'_script' => [
'script' => "for(i:scoring) { if(doc[\"custom_44\"].value == i.id) return i.score; } return 0;",
"type" => "number",
'params' => [
'scoring' => [
['id'=>'3MS01',"score" => 1],
['id'=>'29xcs',"score" => 2],
]
],
"order" => "asc"
]
and my working query body is below
Array
(
[size] => 20
[from] => 0
[query] => Array
(
[filtered] => Array
(
[filter] => Array
(
[bool] => Array
(
[must] => Array
(
[0] => Array
(
[bool] => Array
(
[should] => Array
(
[0] => Array
(
[query] => Array
(
[span_near] => Array
(
[clauses] => Array
(
[0] => Array
(
[span_multi] => Array
(
[match] => Array
(
[regexp] => Array
(
[custom_44] => .*3MS01.*
)
)
)
)
)
[slop] => 0
[in_order] => 1
)
)
)
[1] => Array
(
[query] => Array
(
[span_near] => Array
(
[clauses] => Array
(
[0] => Array
(
[span_multi] => Array
(
[match] => Array
(
[regexp] => Array
(
[custom_44] => .*29xcs.*
)
)
)
)
)
[slop] => 0
[in_order] => 1
)
)
)
)
)
)
[1] => Array
(
[term] => Array
(
[deleted] => 0
)
)
[2] => Array
(
[terms] => Array
(
[publication_id] => Array
(
[0] => 35627
)
)
)
[3] => Array
(
[term] => Array
(
[custom_61] => 1
)
)
)
)
)
)
)
[sort] => Array
(
[0] => Array
(
[custom_44] => asc
)
)
)
Is this can be achieved in the elastic search? Do I need to sort after getting the results?

ElasticSearch will sort the results based on the scoring of the specific field in comparison to your input.
For example , if you search for "Z1234 S1234 T2344" it will try to find documents as close as possible to the individual inputs and the analyzer and then it will rank the results accordingly based on the proximity score.
For example , consider the following index :
POST test/doc/
{
"product_name" : "Z1234"
}
POST test/doc/
{
"product_name" : "Z1235"
}
POST test/doc
{
"product_name" : "S1234"
}
POST test/doc
{
"product_name" : "T2344"
}
If you search for "Z1234 S1234 T2344" , it will sort the results based on the score(results closer to your input) and then it will sort the remaining bellow (values such as "Z1235")
GET test/doc/_search
{
"query": {
"match" : {
"product_name" : {
"query" : "Z1234 S1234 T2344",
"operator" : "OR",
"fuzziness": 1
}
}
}
}
"hits": {
"total": 5,
"max_score": 1.2476649,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "AWViqiCOOSSVvlNCAXVu",
"_score": 1.2476649,
"_source": {
"product_name": "Z1234"
}
},
{
"_index": "test",
"_type": "doc",
"_id": "AWViqlZ2OSSVvlNCAXV7",
"_score": 0.6931472,
"_source": {
"product_name": "T2344"
}
},
{
"_index": "test",
"_type": "doc",
"_id": "AWViqj9UOSSVvlNCAXV2",
"_score": 0.51782775,
"_source": {
"product_name": "S1234"
}
},
{
"_index": "test",
"_type": "doc",
"_id": "AWVir1UeOSSVvlNCAXpB",
"_score": 0.23014566,
"_source": {
"product_name": "Z1235"
}
},
{
"_index": "test",
"_type": "doc",
"_id": "AWVirhwlOSSVvlNCAXkQ",
"_score": 0.23014566,
"_source": {
"product_name": "Z1235"
}
}
]
}
}
Now , if you do not want to sort on the scores , but on the field name , the field of the sorting should contain doc values (default by default of Text fields)
GET test/doc/_search
{
"query": {
"match": {
"product_name": {
"query": "Z1234 S1234 T2344",
"operator": "OR",
"fuzziness": 1
}
}
},
"sort": [
{
"product_name.keyword": {
"order": "desc"
}
}
]
}
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 4,
"max_score": null,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "AWVitbfmOSSVvlNCAYA8",
"_score": null,
"_source": {
"product_name": "Z1235"
},
"sort": [
"Z1235"
]
},
{
"_index": "test",
"_type": "doc",
"_id": "AWVita_pOSSVvlNCAYA7",
"_score": null,
"_source": {
"product_name": "Z1234"
},
"sort": [
"Z1234"
]
},
{
"_index": "test",
"_type": "doc",
"_id": "AWVitcPKOSSVvlNCAYBA",
"_score": null,
"_source": {
"product_name": "T2344"
},
"sort": [
"T2344"
]
},
{
"_index": "test",
"_type": "doc",
"_id": "AWVitb1GOSSVvlNCAYA_",
"_score": null,
"_source": {
"product_name": "S1234"
},
"sort": [
"S1234"
]
}
]
}
}

Related

Sort a multidimensional array in PHP by a given value

I have the following structure:
{
"data": {
"array_1": [
{
"name": "Robert Kalani"
},
{
"name": "Balkan Boy",
}
],
"array_2": [
{
"name": "Pepe Dolan"
},
{
"name": "John Nolan",
}
],
"array_3": [
{
"name": "Phillip A. Luna",
},
{
"name": "Eugene Garcia"
}
]
}
}
I would like to sort each array by the name key in alpabetical order, not sure on how to do that, I've read about array_multisort but it seemed not to work. Would greatly appreciate some help
Here is the expected output
{
"data": {
"array_1": [
{
"name": "Balkan Boy",
},
{
"name": "Robert Kalani"
}
],
"array_2": [
{
"name": "John Nolan"
},
{
"name": "Pepe Dolan"
}
],
"array_3": [
{
"name": "Eugene Garcia"
},
{
"name": "Phillip A. Luna"
}
]
}
}
// Your JSON Data
$data = '{
"data": {
"array_1": [{ "name": "Robert Kalani" }, { "name": "Balkan Boy" }],
"array_2": [{ "name": "Pepe Dolan" }, { "name": "John Nolan" }],
"array_3": [{ "name": "Phillip A. Luna" }, { "name": "Eugene Garcia" }]
}
}
';
$result = [];
// Convert your JSON data to associative array
$array = json_decode($data, true)['data'];
function sort_by_name($a, $b)
{
return $a > $b;
}
foreach ($array as $item) {
uasort($item, "sort_by_name");
$result[] = $item;
}
echo "<pre>";
print_r($result);
Result:
Array
(
[0] => Array
(
[1] => Array
(
[name] => Balkan Boy
)
[0] => Array
(
[name] => Robert Kalani
)
)
[1] => Array
(
[1] => Array
(
[name] => John Nolan
)
[0] => Array
(
[name] => Pepe Dolan
)
)
[2] => Array
(
[1] => Array
(
[name] => Eugene Garcia
)
[0] => Array
(
[name] => Phillip A. Luna
)
)
)

php print json output data in group

I have this output results from database:
Array
(
[0] => stdClass Object
(
[name] => attr one
[attribute_id] => 1
[attribute_group] => group one
[attribute_group_id] => 1
)
[1] => stdClass Object
(
[name] => attr two
[attribute_id] => 2
[attribute_group] => group one
[attribute_group_id] => 1
)
[2] => stdClass Object
(
[name] => attr three
[attribute_id] => 3
[attribute_group] => group one
[attribute_group_id] => 1
)
[3] => stdClass Object
(
[name] => attr four
[attribute_id] => 4
[attribute_group] => group two
[attribute_group_id] => 2
)
)
now for json ouput:
foreach ($results as $result) {
$json[] = array(
'id' => $result->attribute_group_id,
'text' => $result->attribute_group,
'children' => [array(
'id' => $result->attribute_id,
'text' => $result->name,
)]
);
}
return json_encode($json);
output is:
[
{
"id":"1",
"text":"group one",
"children":[
{
"id":"1",
"text":"attr one"
}
]
},
{
"id":"1",
"text":"group one",
"children":[
{
"id":"2",
"text":"attr two"
}
]
},
{
"id":"1",
"text":"group one",
"children":[
{
"id":"3",
"text":"attr three"
}
]
},
{
"id":"2",
"text":"group two",
"children":[
{
"id":"4",
"text":"attr four"
}
]
}
]
But In Action I need to output grouped by attribute_group and listed in children like this:
[
{
"id":"1",
"text":"group one",
"children":[
{
"id":"1",
"text":"attr one"
},
"id":"2",
"text":"attr two"
},
{
"id":"3",
"text":"attr three"
}
]
},
{
"id":"2",
"text":"group two",
"children":[
{
"id":"4",
"text":"attr four"
}
]
}
]
how do can i create this json output?!
Instead of creating an array $json with an element for each attribute, you should gather each attribute directly by attribute_group_id.
In order to do that, the idea is to use the attribute_group_id as the key of your $json array ($json[$result->attribute_group_id]). If an entry already exists for $json[$result->attribute_group_id]['children'] then you just have to had the current children to this item. If not, you create the entry for the current attribute group ID with his information (id,text,children).
Finally you can return the $json without the key that we used for grouping the attributes using array_values (returns the values of an array without keys).
foreach ($results as $result) {
if(isset($json[$result->attribute_group_id]['children'])){
$json[$result->attribute_group_id]['children'][] = array(
'id' => $result->attribute_id,
'text' => $result->name,
);
}
else {
$json[$result->attribute_group_id] = array(
'id' => $result->attribute_group_id,
'text' => $result->attribute_group,
'children' => [array(
'id' => $result->attribute_id,
'text' => $result->name,
)]
);
}
}
return json_encode(array_values($json));
Result :
[
{
"id": "1",
"text": "group one",
"children": [
{
"id": "1",
"text": "attr one"
},
{
"id": "2",
"text": "attr two"
},
{
"id": "3",
"text": "attr three"
}
]
},
{
"id": "2",
"text": "group two",
"children": [
{
"id": "4",
"text": "attr four"
}
]
}
]

ADFORM API PHP Metrics - NEWB Warning

I'm a newb when it comes to PHP and API's so please forgive me if I make any mistakes in terminology etc.
I'm creating an API to call Data from ADFORM reports, and have issues in selecting various metrics.
I make a POST to https://api.adform.com/v1/reportingstats/agency/reportdata
{
"dimensions": [
"client",
"campaign"
],
"metrics": [
"clicks",
"impressions"
],
"filter": {
"date": "campaignStartToEnd"
}
}
The response:
Array
(
[reportData] => Array
(
[columnHeaders] => Array
(
[0] => client
[1] => campaign
[2] => clicks
[3] => impressions
)
[columns] => Array
(
[0] => Array
(
[key] => client
)
[1] => Array
(
[key] => campaign
)
[2] => Array
(
[key] => clicks
[specs] => Array
(
[dataSource] => adform
[adUniqueness] => all
)
)
[3] => Array
(
[key] => impressions
[specs] => Array
(
[dataSource] => adform
[adUniqueness] => all
)
)
)
In the response the adUniqueness = "all" which is a default however from the Adform documentation (http://api.adform.com/help/references/buyer-solutionsc/reporting/metadata/metrics) there are other statistics for uniqueness level.
{
"metricsMetadata": [
{
"key": "clicks",
"category": "Delivery",
"displayName": "Clicks",
"displayFormat": "n0",
"description": "This metric shows the number of clicks for the selected dimension. A click occurs when a user interacts with the advertisement by engaging a mouse button (usually the left) while the mouse pointer is hovering over the advertisement.",
"specsMetadata": [
{
"key": "adUniqueness",
"displayName": "Uniqueness",
"description": "Display statistics for selected uniqueness level",
"specValuesMetadata": [
{
"key": "all",
"displayName": "All",
"isDefault": true,
"description": ""
},
{
"key": "campaignUnique",
"displayName": "Campaign unique",
"isDefault": false,
"description": ""
}
]
}
]
}
How do I add the "campaignUnique" to the POST?
{
"dimensions": [
"client",
"campaign"
],
"metrics": [
{
"metric": "impressions",
"specs": {
"adUniqueness": "campaignUnique"
}
},
{
"metric": "impressions",
"specs": {
"adUniqueness": "all"
}
},
{
"metric": "clicks",
"specs": {
"adUniqueness": "campaignUnique"
}
},
{
"metric": "clicks",
"specs": {
"adUniqueness": "all"
}
}
],
"filter": {
"date": {"from":"2018-01-01", "to":"2018-02-20"}
}
}

How do we sum individual array elements in MongoDB aggregation query?

Document :
{
"version": "1.0.0",
"actor": {
"objectType": "Agent",
"name": "Test user",
"account": {
"homePage": "http://testing.com/",
"name": "67"
}
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/completed",
"display": {
"en-US": "completed"
}
},
"object": {
"objectType": "Activity",
"id": "http://localhost/action?id=cji",
"definition": {
"type": "http://adlnet.gov/expapi/activities/lesson",
"name": {
"en-US": "ps3"
},
"description": {
"en-US": "ps3"
}
}
},
"timestamp": "2016-10-25T11:21:25.917Z",
"context": {
"extensions": {
"http://localhost/eventinfo": {
"sessionId": "1477393533327",
"starttm": "1477394351210",
"eventtm": "1477394485917",
"course": "cji"
}
},
"contextActivities": {
"parent": [
{
"objectType": "Activity",
"id": "http://localhost/id=cji"
}
]
}
},
"result": {
"duration": "PT2M14.71S",
"score": {
"raw": 6,
"max": 21
}
},
"authority": {
"objectType": "Agent",
"name": "New Client",
"mbox": "mailto:hello#lhd.net"
},
"stored": "2016-10-25T11:20:29.666700+00:00",
"id": "c7039783-371f-4f59-a665-65a9d09a2b7f"
}
We've got this PHP + MongoDB aggregation query:
$condition = array(
array(
'$match' => array(
'client_id' => $CFG->mongo_clientid,
'statement.actor.account.name' => array('$in'=> array('67','192','213')),
'statement.verb.id' => 'http://adlnet.gov/expapi/verbs/completed',
'statement.object.id' => 'http://localhost/action?id=cji'
)),
array(
'$group' => array(
'_id' => '$statement.actor.account.name' ,
//'totalpoints' =>array( '$sum' => array('$last' => '$statement.result.score.raw'))
'laststatement' => array('$last' => '$statement.result.score.raw'),
//'sumtest' => array('$add' => ['$laststatement'])
)
)
);
$cursor = $collection->aggregate($condition);
echo "";
print_r($cursor);
echo "";
which returns this result:
Array
(
[result] => Array
(
[0] => Array
(
[_id] => 192
[laststatement] => MongoInt64 Object
(
[value] => 4
)
)
[1] => Array
(
[_id] => 67
[laststatement] => MongoInt64 Object
(
[value] => 6
)
)
)
[ok] => 1
)
How do we sum [laststatement].[value] of these individual array elements in MongoDB aggregation query?
[laststatement] => MongoInt64 Object
(
[value] => values goes here
)
Also, how do we use $last and $sum together in MongoDB aggregation query?
In my result there are 2 raw scores(last statement) for 2 different id (192,67). I want to sum this scores like 4 + 6 = 10 for all multiple id's but want only the last scores from the last statement. I am unable to use $last and $sum on the line. Please check
Looks like all you want is a single group. So the grouping id should be null. You may want to add a sort if you care for what last record should be. Not tested.
array(
'$group' => array(
'_id' => null ,
'totalpoints' => array( '$sum' => '$statement.result.score.raw')
'laststatement' => array('$last' => '$statement.result.score.raw')
)
)
Here is the mongo shell version.
aggregate([
{
$match :{
"actor.account.name":{$in:["67","192","213"]},
"verb.id":{$eq:"http://adlnet.gov/expapi/verbs/completed"},
"object.id":{$eq:"http://localhost/action?id=cji"}
}
},
{
$group: {
"_id": null,
"totalpoints" : {$sum:"$result.score.raw"},
"laststatement" :{$last:"$result.score.raw"}
}
}
])
Output:
{ "_id" : null, "totalpoints" : 10, "laststatement" : 4 }
Update Changed to include the sum for the last statement from each group. The first grouping is by actor name and returns the last statement from each group. The second grouping sums all the last statement.
aggregate([{
$match: {
"actor.account.name": {
$in: ["67", "192", "213"]
},
"verb.id": {
$eq: "http://adlnet.gov/expapi/verbs/completed"
},
"object.id": {
$eq: "http://localhost/action?id=cji"
}
}
}, {
$group: {
"_id": "$actor.account.name",
"laststatement": {
$last: "$result.score.raw"
}
}
}, {
$group: {
"_id": null,
"totalpoints": {
$sum: "$laststatement"
},
}
}])

PHP array to Json tree format

I want to tranform an php array into an json string to use with JavaScript InfoVis Toolkit formart.
the objective:
InfoVis Demo Tree
Json specification format:
InfoVis-loading and serving JSON data
I have this php array: $my_array :
Array
(
[item_1] => Array
(
[id] => item_1_ID
[name] => item_1_NAME
[data] => item_1_DATA
[children] => Array
(
[door] => Array
(
[id] => door_ID
[name] => door_NAME
[data] => door_DATA
[children] => Array
(
[mozart] => Array
(
[id] => mozart_ID
[name] => mozart_NAME
[data] => mozart_DATA
[children] => Array
(
[grass] => Array
(
[id] => grass_ID
[name] => grass_NAME
[data] => yes
)
[green] => Array
(
[id] => green_ID
[name] => green_NAME
[data] => no
)
[human] => Array
(
[id] => human_ID
[name] => human_NAME
[data] => human_DATA
[children] => Array
(
[blue] => Array
(
[id] => blue_ID
[name] => blue_NAME
[data] => blue_DATA
[children] => Array
(
[movie] => Array
(
[id] => movie_ID
[name] => movie_NAME
[data] => yes
)
)
)
)
)
)
)
)
)
[beat] => Array
(
[id] => beat_ID
[name] => beat_NAME
[data] => yes
)
[music] => Array
(
[id] => music_ID
[name] => music_NAME
[data] => no
)
)
)
)
now if I json_encode($my_array);
{
"item_1": {
"id": "item_1_ID",
"name": "item_1_NAME",
"data": "item_1_DATA",
"children": {
"door": {
"id": "door_ID",
"name": "door_NAME",
"data": "door_DATA",
"children": {
"mozart": {
"id": "mozart_ID",
"name": "mozart_NAME",
"data": "mozart_DATA",
"children": {
"grass": {
"id": "grass_ID",
"name": "grass_NAME",
"data": "yes"
},
"green": {
"id": "green_ID",
"name": "green_NAME",
"data": "no"
},
"human": {
"id": "human_ID",
"name": "human_NAME",
"data": "human_DATA",
"children": {
"blue": {
"id": "blue_ID",
"name": "blue_NAME",
"data": "blue_DATA",
"children": {
"movie": {
"id": "movie_ID",
"name": "movie_NAME",
"data": "yes"
}
}
}
}
}
}
}
}
},
"beat": {
"id": "beat_ID",
"name": "beat_NAME",
"data": "yes"
},
"music": {
"id": "music_ID",
"name": "music_NAME",
"data": "no"
}
}
}
}
But to InfoVis the current json output (json_encode($my_array)) has 3 problems:
is not using [ ]
the 'children' arrays have the key names
arrays items is with their key names -> example: "item_1": { ....
let me point the problem so maybe you can help with an function to transform this json string:
see this slice of json_encode($my_array) output:
{
"item_1": {
"id": "item_1_ID",
"name": "item_1_NAME",
"data": "item_1_DATA",
"children": {
"door": {
"id": "door_ID",
1. problem 1:
{
"item_1": {
we have to remove those keys like: "item_1":
2. problem 2:
"children": {
"door": {
"id": "door_ID",
the correct code for this should be:
"children": [
{
"id": "door_ID",......
"door": was removed... because it`s a key
"children": { => becomes" "children": [
An working example of 'children':
"children": [
{
"id": "grass_ID",
"name": "grass_NAME",
"data": "yes"
},
{
"id": "green_ID",
"name": "green_NAME",
"data": "no"
}
]
to clarify an complete example of WORKING Json InfoVis format:
json = {
id: "node02",
name: "0.2",
children: [{
id: "node13",
name: "1.3",
children: [{
id: "node24",
name: "2.4"
}, {
id: "node222",
name: "2.22"
}]
}, {
id: "node125",
name: "1.25",
children: [{
id: "node226",
name: "2.26"
}, {
id: "node237",
name: "2.37"
}, {
id: "node258",
name: "2.58"
}]
}, {
id: "node165",
name: "1.65",
children: [{
id: "node266",
name: "2.66"
}, {
id: "node283",
name: "2.83"
}, {
id: "node2104",
name: "2.104"
}, {
id: "node2109",
name: "2.109"
}, {
id: "node2125",
name: "2.125"
}]
}, {
id: "node1130",
name: "1.130",
children: [{
id: "node2131",
name: "2.131"
}, {
id: "node2138",
name: "2.138"
}]
}]
};
is it clear to understand?
Hope anyone can help me.. I'm working on this for days!
thank you.
Try this quickie conversion function
function fixit($yourArray) {
$myArray = array();
foreach ($yourArray as $itemKey => $itemObj) {
$item = array();
foreach ($itemObj as $key => $value) {
if (strtolower($key) == 'children') {
$item[$key] = fixit($value);
} else {
$item[$key] = $value;
}
}
$myArray[] = $item;
}
return $myArray;
}
$fixed = fixit($my_array);
$json = json_encode($fixed);
PHP doesn't differentiate between arrays (numeric keys) and associative arrays (string keys). They're all just Arrays. Javascript DOES differentiate. Since you're using string keys, they HAVE to be done as objects ({}) in JS.
You can't tell json_encode to ignore the keys in an array (e.g. your 'children' sub-arrays). That'd mean the produced JSON is NOT the same as the original PHP structure - you've now changed key names.
You'd have to process your array and convert all those children sub-array keys to numbers:
grass -> 0
green -> 1
etc...
so that json-encode could see that it's a numerically keyed PHP array, meaning it'll produce an actual javavscript array ([]), and not an object ({}).
The alternative is writing your own JSON-encoder to do this on-the-fly for you.
This is documented behaviour. An associative array will produce an object literal when JSON stringified with json_encode. Update your original array structure to represent the outcome you want, instead of mangling the produced JSON representation, or wrap your own solution around json_encode for each object.
Edit: attempting a cleanup operation
The code
$original = <your original data-array>; // assumed, I reversed your encoded JSON as test data
// Start by stripping out the associative keys for level 1
$clean = array_values($original);
// Then recursively descend array, and do the same for every children-property encountered
function &recursiveChildKeysCleaner(&$arr) {
// If $arr contains 'children'...
if (array_key_exists('children', $arr)) {
/// ...strip out associative keys
$arr['children'] = array_values($arr['children']);
// ...and descend each child
foreach ($arr['children'] as &$child) {
recursiveChildKeysCleaner($child);
}
}
return $arr;
}
foreach ($clean as &$item) {
recursiveChildKeysCleaner($item);
}
unset($item);
echo json_encode($clean);
Output
[{
"id": "item_1_ID",
"name": "item_1_NAME",
"data": "item_1_DATA",
"children": [{
"id": "door_ID",
"name": "door_NAME",
"data": "door_DATA",
"children": [{
"id": "mozart_ID",
"name": "mozart_NAME",
"data": "mozart_DATA",
"children": [{
"id": "grass_ID",
"name": "grass_NAME",
"data": "yes"
},
{
"id": "green_ID",
"name": "green_NAME",
"data": "no"
},
{
"id": "human_ID",
"name": "human_NAME",
"data": "human_DATA",
"children": [{
"id": "blue_ID",
"name": "blue_NAME",
"data": "blue_DATA",
"children": [{
"id": "movie_ID",
"name": "movie_NAME",
"data": "yes"
}]
}]
}]
}]
},
{
"id": "beat_ID",
"name": "beat_NAME",
"data": "yes"
},
{
"id": "music_ID",
"name": "music_NAME",
"data": "no"
}]
}]

Categories