Amazon's Product API limits us to get only 10 items per page, and only 10 pages at a certain query.
I have developed a code that would almost get all items;
first, I have supplied a params that looks like this:
$item_params = [
"Service" => "AWSECommerceService",
"Operation" => "ItemSearch",
"AWSAccessKeyId" => env('AWS_ACCESS_KEY_ID'),
"AssociateTag" => env('AWS_ASSOCIATE_TAG_ID'),
"SearchIndex" => "HomeGarden",
"ResponseGroup" => "ItemAttributes,SalesRank,Offers",
"Sort" => "-price",
"BrowseNode" => $item_params['BrowseNode'],
"MaximumPrice" => $max_price,
"MinimumPrice" => "0"
];
then, the code will get all items under that browse node (category), SORTED BY PRICE (desc) also by specifying the MAX and MIN Price of the items to limit the search.
the pseudo-code (original code is too long)
function getProducts($item_params, $max_price = null){
$products = //request to amazon
foreach ($product as $key=>$value){
//add product to db
}
// if the total number of results on the query is not equal to zero, continue looping
if (!$products->totalResults() == 0){
$product = //get the first lowest priced item on the db
$this->getProducts($item_params, $product->price);
}
}
however I am experiencing this scenario :
Sample request output (assuming all items from amazon):
ASIN(unique id) | Price
1 | 201
2 | 194
3 | 195
.
.
n | 33
n+1 | 33
n+2 | 33
.
n+120 | 33
n+121 | 34
n+122 | 35
wherein the products from n to n+120 are equal. This will create an infinite loop to my getProducts function. How can I avoid this? Knowing that only 10 items are returned on each request and only 10 pages.
How can I avoid this?
I don't think you can with just using price. You have to divide your search into multiple sub-searches by using additional keywords. For example, if you're searching for "laptop", instead do searches on "laptop asus", "laptop dell", etc.
You can also filter on Browse node IDs, so if your results come from multiple browse nodes, you can do two or more searches.
Add the ItemPage parameter and increment it in a loop. You should be able to get up to 100 unique ASINs (10 pages of 10 products per page).
$page = 1;
while($page <= 10) {
$item_params = [
"Service" => "AWSECommerceService",
"Operation" => "ItemSearch",
"AWSAccessKeyId" => env('AWS_ACCESS_KEY_ID'),
"AssociateTag" => env('AWS_ASSOCIATE_TAG_ID'),
"SearchIndex" => "HomeGarden",
"ResponseGroup" => "ItemAttributes,SalesRank,Offers",
"Sort" => "-price",
"BrowseNode" => $item_params['BrowseNode'],
"MaximumPrice" => $max_price,
"MinimumPrice" => "0",
"ItemPage" => $page
];
// execute query and save data
//increment page number
$page++;
}
Related
I need to divide my search result into two parts. 1 with those goods in which the number> 0 sort them by price and withdraw first. 2 products whose quantity = 0 sort by price and display at the end, after those products that are in stock. The main thing is that in the first group of goods (whose quantity> 0) there were no goods from the second group (whose quantity = 0) What unfortunately happens when I sort by two conditions
Use PHP 7.1
and Elastic Search 6.6.0
Small example, there is a table of goods
id | site_price | count
1 | 10 | 0
2 | 5 | 5
3 | 15 | 2
4 | 20 | 10
5 | 15 | 0
I need to sort first by quantity, and then by price (without losing the first sorting).
First sort: ('count'=>'desc').
Second sort: ('site_price'=>'asc').
Should get this result:
id | site_price | count
2 | 5 | 10
3 | 15 | 5
4 | 20 | 2
1 | 10 | 0
5 | 15 | 0
$this->params['body'] = array(
'from' => ($filters['page'] - 1) * 15,
'size' => 15,
'query' => array(
'bool' => array(
'must' => array(
"query_string" => array(
'query' => "*" . $filters['text'] . "*",
)
),
)
),
'sort' => array(
array("shops_count" => "desc"),
array("site_price" => "asc")
)
);
$result = $this->client->search($this->params);
It looks like that you want to achieve behavior similar to UNION in SQL, since you first want to split the result set into 2 groups, sort each group and then attach one group after another.
There are a few ways to do it.
1) By doing 2 queries
Like in this answer, it is suggested to do 2 queries:
POST /orders/_search
{
"query": {
"range": {
"count": {
"gt": 0
}
}
},
"sort" : [
{"site_price": "asc"},
]
}
POST /orders/_search
{
"query": {
"range": {
"count": {
"gte": 0,
"lte": 0
}
}
},
"sort" : [
{"site_price": "asc"},
]
}
And then joining them on the client side.
There is also a way to do it completely on the Elasticsearch side.
2) By using script sorting
We can use script based sorting and sort first on the availability (count > 0), then by price:
POST /orders/_search
{
"sort" : [
{
"_script" : {
"type" : "number",
"script" : {
"lang": "painless",
"source": "if (doc['count'].value > 0) { 1 } else { 0 } "
},
"order" : "desc"
}
},
{"site_price": "asc"}
]
}
However, scripting always has performance overhead. Solution #1 is more robust, although it performs 2 queries.
Here is another solution that uses single query and does not use expensive scripting.
3) Adding new field - for sorting
If we add a special field, "available", we will not need to use script sorting.
The documents might look like this:
doc1 = {
"id": 1,
"site_price": 10,
"count": 0,
"available": 0
}
doc2 = {
"id": 2,
"site_price": 5,
"count": 5,
"available": 1
}
Then the sorting will look like this:
POST /orders/_search
{
"sort" : [
{"available": "desc"},
{"site_price": "asc"}
]
}
This is a common pattern called denormalization which proves useful when tuning for best performance.
Hope that helps!
#Nikolay, thanks for the help.
Unfortunately, this did not help. I tried rewrote the query - but the result is the same. Here is an example: removed too much left only search and sorting
enter code here
$this->params['body'] = array(
'from' => ($filters['page'] - 1) * 15,
'size' => 15,
'query' => array(
'bool' => array(
'must' => array(
"query_string" => array(
'query' => "*" . $filters['text'] . "*",
)
),
)
),
'sort' => array(
array("shops_count" => "desc"),
array("site_price" => "asc")
)
);
$result = $this->client->search($this->params);
Rank Result data set
i am building meta search tool which get results from different sources in response to user query. i have saved the results in array of object having information like title, description , release date etc.before showing it on interface i want to rank them, so that most relevant result should be on top just like search engines. but i am new to ranking and don't know about it. so kindly guide me in this matter which ranking algorithm i should follow or any useful link for help.
I think you need to add "weighting" column (can be null) on your array of Object and just before to show the elements you need to loop on weighting if they got one.
Then your results will be shown in first and if no weight just the normal display.
Here an example :
<?php
//Function to compare weightings
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$searches = array(
'songs'=> array(
0 => array(
'title' => 'coldplay',
'weight'=> 3
),
1 => array(
'title' => 'eminem',
'weight'=> 2
),
2 => array(
'title' => 'rihanna',
'weight'=> 2
),
3 => array(
'title' => 'shakira',
'weight'=> 1
),
4 => array(
'title' => 'nirvana',
'weight'=> null
),
5 => array(
'title' => 'acdc'
)
),
);
//this foreach is used to apply the weighting on itterations
foreach($searches['songs'] as $key => $search){
//if no weight of weight is null
if(array_key_exists('weight', $search) && $search['weight']){
$array_by_weight[$key]['weight'] = $search['weight'];
$array_by_weight[$key]['title'] = $search['title'];
}else{
$array_by_weight[$key]['weight'] = 5; //Value max of weighting
$array_by_weight[$key]['title'] = $search['title'];
}
}
//We use our function to compare and sort our array
uasort($array_by_weight, 'cmp');
//display
foreach($array_by_weight as $songs){
echo $songs['title'].' | ';
echo $songs['weight'].PHP_EOL;
}
Output :
shakira | 1
eminem | 2
rihanna | 2
coldplay | 3
acdc | 5
nirvana | 5
I hope it can help you.
$params = array(
"ll" => "$lat,$lng",
"llAcc" => "100000", //"100";
"radius"=> "100000",
"categoryId"=>"4d4b7105d754a06374d81259",
"venuePhotos" => 1,
"price" => $price,
"sortByDistance" => 1,
"limit" => $limit,
"offset" => $offset,
"intent" => "global"
);
$response = $this->foursquareapi->GetPublic("venues/explore",$params);
Is it possible to filter the venues using the price parameter or what is the other way??
Price parameter does not work for all the countries as per my experience. It works for venues from certain countries like united kingdom,austria,belgium,united states. But same time it does not work for the venues from the countries like Australia,India,etc.
According to the explore api endpoint price should be used as following:
Comma separated list of price points. Currently the valid range of price points are [1,2,3,4], 1 being the least expensive, 4 being the most expensive. For food venues, in the United States, 1 is < $10 an entree, 2 is $10-$20 an entree, 3 is $20-$30 an entree, 4 is $30 an entree.
As such, if you are passing in the relevant values to your price key it should be returning filtered venues as appropriate
I want to get maximum number of products for any specified browsenodeid. I am trying this by executing operation in loop and increase ItemPage by 1. Here is my code:
for($i = 1; $i <= 10; $i++):
$sin = array(
"Operation" => "ItemSearch",
"SearchIndex" => $cat_name,
"BrowseNode" => $browse_node_id,
"ItemPage" => $i,
"Condition" => "All",
"ResponseGroup" => "Medium, Reviews, OfferFull",
"MerchantId" => "Amazon"
);
endfor;
But if i run this till 11 in while loop, it does not return any result for pages more than 10 . But on Amazon it is showing results on 400 pages.
The API will not return more than 10 result pages for any search. One way of getting more results is to set MinimumPrice and MaximumPrice so that you get 10 or fewer pages and then adjust the range and repeat.
I have the following values from a database call that I want to apply some logic to. I thought I could originally use PHP's max however this doesn't appear to be the case.
I have three suppliers of a product. They might not all stock the item I am displaying, and they all offer a different margin, on a product by product basis though, so that is why I can't just say generally supplier 1 is better than supplier 2 etc.
$supplier1Live = 1
$supplier2Live = 1
$supplier3Live = 0
$marginSupplier1 = 20
$marginSupplier2 = 40
$martinSupplier3 = 50
In this example I would want to use Supplier 2 as they stock the product supplier2Live = 1 and also have the better margin than the other supplier who stocks the product (supplier1)
My mind however is drawing a complete blank in how to code this?
I thought I could add it to an array giving:
$array = array(
"supplier1" => array(
"live" => 1,
"margin" => 20
),
"supplier2" => array(
"live" => 1,
"margin" => 40
),
"supplier3" => array(
"live" => 0,
"margin" => 50
)
);
And run something on that, but not sure what to.
Filter the array using array_filter (filter by live==1), and then find the maximum out of the resultant array (maximum on the "margin" value)
Like this, if I understand correctly
$array = array(
"supplier1" => array(
"live" => 1,
"margin" => 20
),
"supplier2" => array(
"live" => 1,
"margin" => 40
),
"supplier3" => array(
"live" => 0,
"margin" => 50
)
);
$res = array_filter($array,function($v){return $v["live"];});
$supplier = array_reduce($res, function($a, $b){
return $a["margin"]>$b["margin"]?$a:$b;
});
print_r($supplier);
Try something like this:
$best_supplier = null;
$best_supplier_margin = null;
foreach($array as $name => $supplier) {
if($supplier['live']) {
if($supplier['margin'] > $best_supplier_margin || is_null($best_supplier_margin)) {
$best_supplier = $name;
$best_supplier_margin = $supplier['margin'];
}
}
}
if(is_null($best_supplier)) throw new Exception('No suppliers are live!');
echo $best_supplier;
So you basically want to find the max of supplierXLive * marginSupplierX?
You can also implement a custom compare function and provide it to PHPs usort() function