Elasticsearch scroll api search "from" - php

I have a script that generates sitemaps based on url index http://example.com/sitemap.index.xml where index is a number >0 that defines what results should be included in each chunk.
$chunk = 10000;
$counter = 0;
$scroll = $es->search(array(
"index" => "index",
"type" => "type",
"scroll" => "1m",
"search_type" => "scan",
"size" => 10,
"from" => $chunk * ($index - 1)
));
$sid = $scroll['_scroll_id'];
while($counter < $chunk){
$docs = $es->scroll(array(
"scroll_id" => $sid,
"scroll" => "1m"
));
$sid = $docs['_scroll_id'];
$counter += count($docs['hits']['hits']);
}
// ...
Now each time I access http://example.com/sitemap.1.xml or http://example.com/sitemap.2.xml the results returned from ES are exactly the same. It returns 50 results (10 per each shard) but does not seem to take count of from = 0, from = 10000.
I'm using elasticsearch-php as ES library.
Any ideas?

In Java, it can be done as follows
QueryBuilder query = QueryBuilders.matchAllQuery();
SearchResponse scrollResp = Constants.client.prepareSearch(index)
.setTypes(type).setSearchType(SearchType.SCAN)
.setScroll(new TimeValue(600000)).setQuery(query)
.setSize(500).execute().actionGet();
while (true) {
scrollResp = Constants.client
.prepareSearchScroll(scrollResp.getScrollId())
.setScroll(new TimeValue(600000)).execute().actionGet();
System.out.println("Record count :"
+ scrollResp.getHits().getHits().length);
total = total + scrollResp.getHits().getHits().length;
System.out.println("Total record count: " + total);
for (SearchHit hit : scrollResp.getHits()) {
//handle the hit
}
// Break condition: No hits are returned
if (scrollResp.getHits().getHits().length == 0) {
System.out.println("All records are fetched");
break;
}
}
Hope it helps.

Related

PHP fake average rating generator

Let's imagine that the material has a rating of 2.7 with 7 votes.
I want to create a script that would generate my desired rating that would look real and not fake.
For example, I want the rating to change from 2.7 to 4.6, but the number of votes should also change proportionally.
I can't figure out how to implement it correctly.
My script will make the rating 6.0 as I want, but as a result the number of votes will be as high as 500+. I want to refine the script so that it is more realistic and changes the rating with minimal votes
My code:
My script will make the rating 6.0 as I want for example, but the number of votes will be as high as 500+. I want to generate the average values of the rating based on the previous values, while the deviation in the votes should not look fake.
<?php
class RatingFaker
{
private $totalRating = 10; // Maximum rating threshold (5 or 10)
private $maxRatingGenerate = 10; // We generate maximum rating values during the passage
private $minRatingGenerarate = 5; // Minimally generates a rating value during a pass
private $minRatingCheck = 3.5; // The minimum acceptable threshold from which we start to act
public function __construct($minRatingCheck)
{
$this->minRatingCheck = $minRatingCheck;
}
private function calcAverageRating($ratings = [])
{
$totalWeight = 0;
$totalReviews = 0;
foreach ($ratings as $weight => $numberofReviews) {
$WeightMultipliedByNumber = $weight * $numberofReviews;
$totalWeight += $WeightMultipliedByNumber;
$totalReviews += $numberofReviews;
}
//divide the total weight by total number of reviews
$averageRating = $totalWeight / $totalReviews;
return [
'rating' => $averageRating,
'vote_num' => $totalReviews
];
}
private function getRandVoters()
{
$randRating = rand($this->minRatingGenerarate, $this->maxRatingGenerate);
$randVoters = rand(1, 99);
return [
$randRating => $randVoters
];
}
private function ratingLoop($valueList)
{
$valueList = array_merge($valueList, $this->getRandVoters());
$newRating = $this->calcAverageRating($valueList);
if($newRating['rating'] < $this->minRatingCheck) {
$valueList = array_merge($valueList, $this->getRandVoters());
return $this->ratingLoop($valueList);
}
if($newRating['rating'] > 10) {
$newRating['rating'] = 10;
}
return [
'rating' => round($newRating['rating'], 1),
'sum' => round($newRating['vote_num'] * round($newRating['rating'], 1)),
'voters' => $newRating['vote_num']
];
}
public function check($currentRate, $currentVoteNum)
{
if($currentRate < $this->minRatingCheck) {
$rating = $this->ratingLoop([
$currentRate => $currentVoteNum,
]);
}
return $rating ?? [];
}
}
$currentRate = 2.4;
$voteNum = 88;
$oldRating = [
'rating' => $currentRate,
'sum' => round($voteNum * $currentRate),
'voters' => $voteNum
];
$rating = [];
$ratingFaker = new RatingFaker(6.0);
$rating = $ratingFaker->check($currentRate, $voteNum);
echo '<pre>';
echo 'Was:';
print_r($oldRating);
echo "<br>";
echo "<br>";
echo "<br>";
echo 'Now:';
print_r($rating);
echo '</pre>';
When the current rating is 2.5 based on 9 votes, and you want to get a rating of 6.0 with a minimal number of votes, you need to make sure the total value of 10 votes is 60 ( 60/10 = 6.0 ).
The current rating is : ( 2.5*9 / 9 ) = 2.5
With you extra vote it is: ( (2.5*9+x) / 10 ) = 6.0
Now you only have to find the correct value for x, which is 37.5

Woocommerce - Implementation of query args in the reviews counting graph only for the currently selected language

I have a code that displays reviews graph of the entire website and divides them into sections according to ratings. The problem is that this code calculates the total reviews of the whole website. I would need to filter the total reviews count according to the currently chosen language. I use WPML. Any advice?
Code:
function display_all_product_review_histogram($minimum_rating, $maximum_rating){
$all_product_review_average_rating = get_all_product_review_average_rating($minimum_rating, $maximum_rating);
$total_ratings = $all_product_review_average_rating[0]["total_ratings"];
$get_all_product_review_counts_by_ratings = get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating);
if($get_all_product_review_counts_by_ratings){
$output = '';
$sum = 0;
$total = 0;
$raw_percentages_array = array();
$percentages_array = array();
//When working with rounded percentages, we must make sure the total percentages add up to 100%.
//Creating array of rating values and its percentage
foreach ($get_all_product_review_counts_by_ratings as $key => $rating) {
$percentage = round($rating["amount"] / $total_ratings, 2) * 100;
$raw_percentages_array[] = array("value" => $rating["value"], "percent_of_total" => $percentage, 'amount'=> $rating["amount"]);
}
//Counting the total of our percents
foreach($raw_percentages_array as $key => $percent) {
$total += $percent[ "percent_of_total" ];
}
//Creating an array that will have the actual percentages after the rounding has been applied to it.
//This will help to see if we have 100% or we are not aligned
foreach($raw_percentages_array as $key => $percent){
$percentages_array[$percent["value"]] = round(($percent["percent_of_total"]/$total) * 100, 0);
}
$sum = array_sum($percentages_array); //Again counting the total of our new percents to see if it adds up to 100%
if($sum != 100){ //If we do not have 100%, then we will alter the highest percentage value so that we get a total of 100%
$highest_percentage_key = array_keys($percentages_array, max($percentages_array)); //Getting key of the highest percentage value
$percentages_array[$highest_percentage_key[0]] = 100 - ($sum - max($percentages_array)); //Alterning the percentage
}
//Now we are ready to create the output that will give us 100% in total
$r_count = 0;
$output .= "<div class='product-review-histogram'>";
foreach ($percentages_array as $key => $percentage) {
$output .= "<div class='histogram-row star-rating-". $key ."'>";
$output .= "<div class='histogram-col-1'>". $key ." star</div>";
$output .= "<div class='histogram-col-2'><div class='histogram-meter-bar'><div class='histogram-bar-temperature' style='width: ". $percentage ."%'></div></div></div>";
$output .= "<div class='histogram-col-3'>". $raw_percentages_array[$r_count]['amount'] ."</div>";
$output .= "</div>";
$r_count++;
}
$output .= "</div>";
return $output;
}else{
return;
}
}
UPDATE - sharing code of get_all_product_review_average_rating function:
function get_all_product_review_average_rating($minimum_rating, $maximum_rating){
$get_all_product_review_counts_by_ratings = get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating);
if($get_all_product_review_counts_by_ratings){ //If we have reviews
$average_rating_results = array();
$total_ratings = 0;
$total_rating_value = 0;
foreach ($get_all_product_review_counts_by_ratings as $key => $rating) {
$total_ratings = $total_ratings + $rating["amount"];
$current_rating_value = $rating["amount"] * $rating["value"];
$total_rating_value = $total_rating_value + $current_rating_value;
}
$average_rating = number_format($total_rating_value / $total_ratings, 1); //Rounding value to one decimal place
$average_rating_results[] = array(
"total_ratings" => $total_ratings,
"average_rating" => $average_rating
);
return $average_rating_results;
}else{
return;
}
}
UPDATE2 - sharing more of the functions related to the graph
function get_all_product_review_ratings(){
global $wpdb;
if ( false === ( $review_ratings = get_transient( 'all_product_review_ratings' ))){ //Checking if we have previously cached query results in order to save resources and increase speed
$review_ratings = $wpdb->get_results("
SELECT meta_value
FROM {$wpdb->prefix}commentmeta as commentmeta
JOIN {$wpdb->prefix}comments as comments ON comments.comment_id = commentmeta.comment_id
WHERE commentmeta.meta_key = 'rating' AND comments.comment_approved = 1
ORDER BY commentmeta.meta_value
", ARRAY_A);
$expiration = 60 * 5; //Expiring query results after 5 minutes
set_transient( 'all_product_review_ratings', $review_ratings, $expiration ); //Temporarily storing cached data in the database by giving it a custom name and a timeframe after which it will expire and be deleted
return $review_ratings;
}else{
return $review_ratings;
}
}
WHAT DO WE NEED TO CHANGE TO GET THIS IS PROBABLY THIS PART OF THE CODE:
$review_ratings = $wpdb->get_results("
SELECT meta_value
FROM {$wpdb->prefix}commentmeta as commentmeta
JOIN {$wpdb->prefix}comments as comments ON comments.comment_id = commentmeta.comment_id
WHERE commentmeta.meta_key = 'rating' AND comments.comment_approved = 1
ORDER BY commentmeta.meta_value
", ARRAY_A);
UPDATE 3:
function get_all_product_review_counts_by_ratings($minimum_rating, $maximum_rating){
$all_product_review_ratings = get_all_product_review_ratings();
if($all_product_review_ratings){ //If we have reviews
$all_product_review_ratings_one_dimensional_array = array_map("current", $all_product_review_ratings); //Converting two dimensional array to one dimensional array
$rating_counts = array_count_values($all_product_review_ratings_one_dimensional_array); //Creating array that consists of rating counts
$ratings = array();
while($maximum_rating >= $minimum_rating){
if(array_key_exists($maximum_rating, $rating_counts)){
$star_count = $rating_counts[$maximum_rating];
}else{
$star_count = 0;
}
//Creating array that contains information about
$ratings[] = array(
"value" => $maximum_rating,
"amount" => $star_count
);
$maximum_rating--;
}
return $ratings;
}else{
return;
}
}
function get_all_product_review_ratings() {
global $wpdb;
if (false === ( $review_ratings = get_transient('all_product_review_ratings'))) { //Checking if we have previously cached query results in order to save resources and increase speed
$review_ratings = array();
$args = array(
'status' => 'approve',
'type' => 'review',
'paged' => 0,
'meta_query' => array(
array(
'key' => 'verified',
'value' => 1
)
));
// The Query for getting reviews - WPML respected
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query($args);
foreach ($comments as $comment) {
$review_ratings[] = get_comment_meta($comment->comment_ID, 'rating', 1);
}
$expiration = 60 * 5; //Expiring query results after 5 minutes
set_transient('all_product_review_ratings', $review_ratings, $expiration); //Temporarily storing cached data in the database by giving it a custom name and a timeframe after which it will expire and be deleted
return $review_ratings;
} else {
return $review_ratings;
}
}

Elasticsearch scroll scan query doesn't return all documents, missing first set

I'm trying to scroll my ES index and grab all the documents but it looks like I keep missing the first set of documents returned by the initial scroll. For example if my scroll size is 10 and my query returns a total of 100 after scrolling I would only have 90 documents. Any suggestions on what I'm missing?
Here's what I've currently tried:
$json = '{"query":{"bool":{"must":[{"match_all":{}}]}}}';
$params = [
"scroll" => "1m",
"size" => 50,
"index" => "myindex",
"type" => "mytype",
"body" => $json
];
$results = $client->search($params);
$scroll_size = $results['hits']['total']; // returns total docs that match query
$s_id = $results['_scroll_id'];
print " total results: " . $scroll_size;
//scroll
$count = 0;
while ($scroll_size > 0) {
print " SCROLLING...";
$scroll_results = $client->scroll([
'scroll_id' => $s_id,
'scroll' => '1m'
]);
// get number of results returned in the last scroll
$scroll_size = sizeof($scroll_results['hits']['hits']);
print " scroll size: " . $scroll_size;
// do something with results
for ($i=0; $i<$scroll_size; $i++) {
$count++;
}
}
print " total id count: " . $id_count;
the first query you execute to return number of documents, also returns documents. The first query is to establish the scroll and also to get the first set of documents. Once you process the first set of results, you can use the scroll_id to get the next page and so on.
Thanks #Ramdev. Yeah I realized that after a little digging. For anyone else Here's what ended up working for me:
$json = '{"query":{"bool":{"must":[{"match_all":{}}]}}}';
$count = 0;
$params = [
"scroll" => "1m",
"size" => 50,
"index" => "myindex",
"type" => "mytype",
"body" => $json
];
$results = $client->search($params);
$scroll_size = $results['hits']['total']; // returns total docs that match query
$s_id = $results['_scroll_id'];
print " total results: " . $scroll_size;
// first set of scroll results
for ($i=0; $i<$size; $i++) {
$count++;
}
//scroll
while ($scroll_size > 0) {
print " SCROLLING...";
$scroll_results = $client->scroll([
'scroll_id' => $s_id,
'scroll' => '1m'
]);
// get number of results returned in the last scroll
$scroll_size = sizeof($scroll_results['hits']['hits']);
print " scroll size: " . $scroll_size;
// do something with results
for ($i=0; $i<$scroll_size; $i++) {
$count++;
}
}
print " total id count: " . $id_count;

Translate HTML form request to php array

I have a html form with 3 selector:
a. Room -> 1, 2, 3, 4, 5, 6
b. Adults -> 1, 2, 3, 4, 5, 6
c. Childs -> 0, 1, 2, 3, 4, 5
THe php arrays that i need to get looks like:
Example 1 room with 2 adults
$rooms[] = array(array("paxType" => "Adult"), array("paxType" => "Adult"));
Example 2 rooms ( one room is with two adults and the second room si with 2 adults an
one child
$rooms[] = array(array("paxType" => "Adult"), array("paxType" => "Adult"));
$rooms[] = array(array("paxType" => "Adult"), array("paxType" => "Adult"), array("paxType" =>"Child", "age" => 8));
The variables that i receive from the form are as below:
$City= $_POST['City']; - text
$CheckIN= $_POST['CheckIN']; - text (date)
$CheckOUT= $_POST['CheckOUT']; - text (date)
$Rooms= $_POST['Rooms']; - selector (1,2,3,4,5,6)
$Adults= $_POST['Adults']; - selector (1,2,3,4,5,6)
$Childs= $_POST['Childs']; - selector (0,1,2,3,4,5)
Form is workink fine for text and date input fields.
How can i translate the html form request to get into the a bove look like php arrays.
Thank you for your time.
Entire code is:
// create SOAP client object
$client = new SoapClient("http://www.bookingassist.ro/test/book.wsdl", array('trace' => 1));
try {
function addPaxType($type = null, $amount = 0)
{
$pax = array();
for ($i = 0; $i < amount; $i++)
{
array_push($pax, array('paxType' => $type));
}
return $pax;
}
$RoomsLength = 1;//count($_POST['Rooms']);
$Rooms = array();
//iterate over all rooms
for ($i = 0; $i < $RoomsLength ; $i++)
{
$Rooms[$i] = array();
if ( count($Adults) > 0)
{
//use a function to add adults to room
array_push($Rooms[$i] , addPaxType('Adults', count($Adults)));
}
if (count($Childs) > 0)
{
array_push($Rooms[$i], addPaxType('Childs', count($Childs)));
}
}
$filters = array();
$filters[] = array("filterType" => "hotelStar", "filterValue" => "3", "4", "5");
$filters[] = array("filterType" => "resultLimit", "filterValue" => "7");
// make getAvailableHotel request (start search)
$checkAvailability = $client->getAvailableHotel("gfdgdfgVNhTzA4MVZ3Y2hjTkt3QXNHSXZRYUZOb095Qg==", "RHMK", "2015-03-30", "2015-04-12", "EUR", "RO", "false", $rooms, $filters);
}
catch (SoapFault $exception) {
echo $exception->getMessage();
exit;
}
You can get an array setting in the name input method on the html form post
<br />Room: <input type="text" **name="somearray[]"** required/></br>
After that you can do some like this
$room=$_POST['somearray'];
forgive my bad English!
You need a for lus for this. Based upon the data on this page. I cannot define in which rooms the children and adults are and the age of the children based upon the supplied data. I can however show you an attempt to make such an array.
function addPaxType($type = null, $amount = 0)
{
$pax = array();
for ($i = 0; $i < amount; $i++)
{
array_push($pax, array('paxType' => $type));
}
return $pax;
}
$RoomsLength = count($_POST['Rooms']);
$Rooms = array();
//iterate over all rooms
for ($i = 0; $i < $RoomsLength ; $i++)
{
$Rooms[$i] = array();
if ( count($Adults) > 0)
{
//use a function to add adults to room
array_push($Rooms[$i] , addPaxType('adult', count($Adults)));
}
if (count($Childs) > 0)
{
array_push($Rooms[$i], addPaxType('child', count($Childs)));
}
}
When two rooms are selected and two adults this will output:
$Rooms[0] --> [ [paxType => adult], [paxType => adult] ];
$Rooms[1] --> [ [paxType => adult], [paxType => adult] ];

How to format json to what I need?

ok, Going to get this out of the way right now. I suck at php. I am building an angular app that is going to populate a mobile app with data from the database. I having it pull from the database just fine but I need the json formatted in a special way and I have no idea how to do it.
Using json_encode this is how it is coming from the database:
[
{
"id":"1",
"date":"2014-10-03",
"time":"2014-10-03 10:45:05",
"amount":"5"
},
{
"id":"2",
"date":"2014-10-03",
"time":"2014-10-03 12:21:05",
"amount":"2"
}
]
This is how I need it organized (this is just dummy data im using in on the angular side)
[
{
date: '2014-09-04',
feeding: [
{
id: '1',
time: '1409852728000',
amount: '3'
},
{
id: '2',
time: '1409874328000',
amount: '4'
},
]
},
{
date: '2014-09-05',
feeding: [
{
id: '3',
time: '1409915908000',
amount: '3.5'
},
{
id: '4',
time: '1409957908000',
amount: '5'
},
]
},
]
I needs to be seperated out and grouped by date. How would I go about doing this?
Airtech was just about there. Small update to the function though. The feeding value needs to be an array of objects rather than an object. You then need to push individual objects into that array.
function dateparse($in) {
$in = json_decode($in);
$out = array();
for ($i = 0; $i < sizeof($in); $i++) {
$date = $in[$i]->date;
$isFound = false;
for ($i2 = 0; $i2 < sizeof($out); $i2++) {
if ($date == $out[$i2]["date"]) {
// We've already run into this search value before
// So add the the elements
$isFound = true;
$out[$i2]["feeding"][] = array(
"id" => $in[$i]->id,
"time" => $in[$i]->time,
"amount" => $in[$i]->amount);
break;
}
}
if (!$isFound) {
// No matches yet
// We need to add this one to the array
$feeding = array("id" => $in[$i]->id, "time" => $in[$i]->time, "amount" => $in[$i]->amount);
$out[] = array("date" => $in[$i]->date, "feeding" => array($feeding));
}
}
return json_encode($out);
}
How about the following? I tested it on your json input example and it ran fine.
function parse($in)
{
$in = json_decode($in);
$out = array();
for ($i = 0; $i < sizeof($in); $i++) {
$date = $in[$i]->date;
$isFound = false;
for ($i2 = 0; $i2 < sizeof($out); $i2++) {
if ($date == $out[$i2]["date"]) {
// We've already run into this search value before
// So add the the elements
$isFound = true;
$out[$i2][]["feeding"] = array(
"id" => $in[$i]->id,
"time" => $in[$i]->time,
"amount" => $in[$i]->amount);
break;
}
}
if (!$isFound) {
// No matches yet
// We need to add this one to the array
$out[] = array("date" => $in[$i]->date, "feeding" => array(
"id" => $in[$i]->id,
"time" => $in[$i]->time,
"amount" => $in[$i]->amount));
}
}
return json_encode($out);
}
How about this ? This works fine and works as expected :) :-
function dateparse($var)
{
$counter=0; $var = json_decode($var); $date=array();
foreach($var as $key=>$value){foreach($value as $val1=>$val2)
{if($val1 == "date")
{foreach($value as $val3=>$val4)
{if($val3!="date") //because we don't want date again
{
$date[$val2]["feeding"][$counter][$val3] = $val4; continue;
}}continue;
}
}$counter++;}
return json_encode($date);}

Categories