Solr FieldCollapsing for More Like This queries - php

I want to use a "More Like This" query to find similar documents and collapse those that have the same value for the field 'image'. I tried to use the Field Collapsing parameters however they do not seem to work for "More like this".
Below is a snippet of my code. Can you tell me how to collapse results using the "More Like This" query?
$url = "http://{$host}:{$port}/solr/{$core}/mlt";
$data = [
'stream.body' => $content,
'fl' => 'image,content,title,signature',
'start' => 0,
'order' => "score desc",
'wt' => 'json',
'mlt.fl' => 'content,title',
// these lines do nothing ---v
'group' => 'true',
'group.field' => 'image',
'group.sort' => 'impressions desc',
'group.main' => 'true'
];
$curlHandle = curl_init($url);
$options = array (
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $data
);
curl_setopt_array($curlHandle , $options);
$result = json_decode(curl_exec($curlHandle));

General answer
I could not collapse results using Field Collapsing paramaters. However, I was able to achieve the desired result using CollapsingQParserPlugin.
The following filter query collapses documents on the field 'image' and selects the one with the highest value for the field 'impressions': {!collapse field=image max=impressions}
Implementation
For some reason I was not able to combine this filter query with my other filter queries under a single key as follows:
$filterQueries = [
"-signature:{$signature}",
...
"{!collapse field=image max=impressions}"
];
$data = [
...
'fq' => implode(' AND ', $filterQueries),
...
];
This produced the error: Query does not implement createWeight
My fix was to do a GET request (instead of a POST, which was done in the question above). With the GET request it is possible to have a key for each filter query: http://solr-url/mtl?...&fq=-signature%3A0&...&fq=%7B!collapse+field%3Dimage+max%3Dimpressions%7D
Below is the php solution for the snippet in the question:
$url = "http://{$host}:{$port}/solr/{$core}/mlt?"; // Note the added question mark
$data = [
'stream.body' => $content,
'fl' => 'image,content,title,signature',
'fq' => $filterQueries,
'start' => 0,
'order' => "score desc",
'wt' => 'json',
'mlt.fl' => 'content,title'
];
$params = [];
foreach ($data as $key=>$value) {
if (is_array($value)) {
foreach ($value as $subvalue) {
$subvalue = urlencode($subvalue);
$params[] = "{$key}={$subvalue}";
}
} else {
$value = urlencode($value);
$params[] = "{$key}={$value}";
}
}
$url .= implode('&', $params);
$curlHandle = curl_init($url);
$options = array ();
curl_setopt_array($curlHandle , $options);
$result = json_decode(curl_exec($curlHandle));

Related

How to loop multidimensional array from mysql table with php

After reading muiltiple stackoverflow questions I'm still confused on why I am not able to get this to work. I am attempting to take all of the rows of a mysql table and put them into a multidimensional array. I was hoping to just find a simple example but so far I'm not fully understanding.
The examples I've seen on google and stack is mostly about parsing or making it iterate on the page. I am attempting to have the mysql rows iterate into their arrays. The example code I started working with was similiar to this:
// This will hopefully get all of the categories
case 'get_all_categories' :
$query = '
SELECT `id`,`category_name`, `category_spam`
FROM `category`
';
if (!$go = #mysql_query($query)) {
$results = Array(
'head' => Array(
'status' => '0',
'error_number' => '604',
'error_message' => 'Select Failed. '.
'Probably wrong name supplied.'
),
'body' => Array ()
);
} else {
$fetch = mysql_fetch_row($go);
$return = Array($fetch[0],$fetch[1]);
$results = Array(
'body' => Array (
'id' => $return[0],
'category_name' => $return[1]
)
);
}
break;
This obviously provides me with the result of just ONE as that is what I'm asking it to do with fetch_row.
i.e.
//outputs
{"body":{"id":"1","category_name":"Star Wars"}}
I've attempted to use mysql_fetch_assoc and then do a foreach loop?
I"ve also tried doing a mysql_fetch_all($go) and then attempt to put the rows into it.
if (!$go = #mysql_query($query)) {
$results = Array(
'head' => Array(
'status' => '0',
'error_number' => '604',
'error_message' => 'Select Failed. '.
'Probably wrong name supplied.'
),
'body' => Array ()
);
} else {
while($myrow = mysql_fetch_row($go)){
Array(
'body' => Array(
'id' => $myrow[o],
'category_name' => $myrow[1],
'category_spam' => $myrow[2]
)
}
);
}
break;
I am attempting to make an api call where the body holds all of the categories and their id's (the point I believe is then for the categories to pull and show the lists...which I'm hoping is the right away to make an api(not a question just rambling)
So: how do I make the query take all of the mysql rows and loop them into arrays for the body array. (note: I'm new to API's if my terminology is wrong to what my overall goal is which is to get an api call to show my whole mysql array then please let me know).
EDIT Just adding more info from the comments
The output is JSON encoded (sorry I should have explained that)
switch ($_GET['format']) {
case 'xml' :
#header ("content-type: text/xml charset=utf-8");
$xml = new XmlWriter();
$xml->openMemory();
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('callback');
$xml->writeAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');
$xml->writeAttribute('xsi:noNamespaceSchemaLocation','schema.xsd');
function write(XMLWriter $xml, $data){
foreach($data as $key => $value){
if(is_array($value)){
$xml->startElement($key);
write($xml, $value);
$xml->endElement();
continue;
}
$xml->writeElement($key, $value);
}
}
write($xml, $results);
$xml->endElement();
echo $xml->outputMemory(true);
break;
case 'json' :
#header ("content-type: text/json charset=utf-8");
echo json_encode($results);
break;
case 'php' :
header ("content-type: text/php charset=utf-8");
echo serialize($results);
break;
}
$res = mysql_query($query);
$results = array();
$i = 0;
while($row=mysql_fetch_array($res)) {
$results['body'][$i]['id'] = $row[o];
$results['body'][$i]['category_name'] = $row[1];
$results['body'][$i]['category_spam'] = $row[2];
$i++;
}
if(empty($results['body'])){
$results['head'] = Array(
'status' => '0',
'error_number' => '604',
'error_message' => 'Select Failed. '.
'Probably wrong name supplied.'
);
}
break;
Try the above code it will create $result array for your json response.
Rest everything is fine!

Get count of each element returned by mysql query

This is my query:
SELECT `Brand`,`Colour`,`Occassion`,`Fabric`,`Type`
FROM `deals`
WHERE `Size`
LIKE '%XS%';
It returns 35 results. Now, what i want is a count of each of the columns (Brand, colour etc) which are present in the above resultset to create a histogram. I am not sure about how to do this.
Any help is appreciated.
I think ideal result should look like this:
$data = array(
"Brand" => array(brand1 => 1, brand2 => 2),
"Colour" => array(colour1 => 1, colour2 => 2),
"Occassion" => array(Occassion1 => 1, Occassion2 => 2),
);
For each subarray we can draw a histogram. The code will look like this:
$query = "
SELECT
`Brand`,`Colour`,`Occassion`,`Fabric`,`Type`
FROM
`deals`
WHERE
`Size` LIKE '%XS%'";
$data = array(
"Brand" => array(),
"Colour" => array(),
"Occassion" => array(),
"Fabric" => array(),
"Type" => array(),
);
if ($result = $mysqli->query($query)) {
/* fetch associative array */
while ($row = $result->fetch_assoc()) {
foreach($row as $key => $value)
{
$data[$key][$value]++;
}
}
/* free result set */
$result->free();
}
Or we can define $data subarrays inside foreach to make the program more flexible:
$data = array();
...
foreach($row as $key => $value)
{
if(!isset($data[$key]))
{
$data[$key] = array();
}
$data[$key][$value]++;
}
...

PHP - good practice reading POST variables

I am thinking of a good practice to read the client submitted POST data.
For example if I have a post variable that should have the following structure:
array(
[0] => array(
['test'] => array(1, 2, 3),
['test2'] => "string"
),
[1] => array(
['test'] => array(),
['test2'] => "string2"
),
)
Where the indices 'test' and 'test2' should always be present but their values may be empty (array() and "");
The functions that handle the POST data are expecting the correct format, so I have to make sure that the data has not been manipulated.
I could do the following:
$result = array();
if(isset($_POST['myVar']) && is_array($_POST['myVar'])) {
foreach($_POST['myVar'] as $array) {
$new = array('test' => array(), 'test2' = "");
if(isset($array['test']) && is_array($array['test'])) {
foreach($array['test'] as $expectedInt) {
$new['test'][] = (int)$expectedInt;
}
}
if(isset($array['test2']) && is_string($array['test2']))
$new['test2'] = $array['test2'];
}
$result[] = $new;
}
I think you get the idea what I mean. I wonder if there is a better practice of reading the POST data into the expected format.
I usually do this to assure I have default indices:
$par = $_POST;
$par += [
'key' => 'default',
'other' => 'default',
]
If $par doesn't contain those keys, they are set.
In your case, your could do this:
$ready = [];
foreach($_POST as $k => $v){
$v += [
'test' => [],
'test2' => "string2",
];
// Validate if needed
$v['test'] = (array)$v['test'];
$v['test2'] = (string)$v['test2'];
$ready[$k] = $v;
}
Later you can be sure, that $ready will contain values with test and test2 keys.
This is very useful in functions, where you replace a lot of arguments with one parameter array, and then later set default values,

Get the sub array in a bidimensional array having a particular key/value pair

I have a large PHP array, similar to:
$list = array(
array(
'id' = '3243'
'link' = 'fruits'
'lev' = '1'
),
array(
'id' = '6546'
'link' = 'apple'
'lev' = '2'
),
array(
'id' = '9348'
'link' = 'orange'
'lev' = '2'
)
)
I want to get the sub-array which contains a particular id.
Currently I use the following code:
$id = '3243'
foreach ($list as $link) {
if (in_array($id, $link)) {
$result = $link;
}
}
It works but I hope there is a better way of doing this.
You can
write $link['id']==$id instead of in_array($id, $link) whitch will be less expensive.
add a break; instruction after $result = $link; to avoid useless loops
While this answer wouldn't have worked when the question was asked, there's quite an easy way to solve this dilemma now.
You can do the following in PHP 5.5:
$newList = array_combine(array_column($list,'id'),$list);
And the following will then be true:
$newList[3243] = array(
'id' = '3243';
'link' = 'fruits'; etc...
The simplest way in PHP 5.4 and above is a combination of array_filter and the use language construct in its callback function:
function subarray_element($arr, $id_key, $id_val = NULL) {
return current(array_filter(
$arr,
function ($subarr) use($id_key, $id_val) {
if(array_key_exists($id_key, $subarr))
return $subarr[$id_key] == $id_val;
}
));
}
var_export(subarray_element($list, 'id', '3243')); // returns:
// array (
// 'id' => '9348',
// 'link' => 'orange',
// 'lev' => '2',
// )
current just returns the first element of the filtered array.
A few more online 3v4l examples of getting different sub-arrays from OP's $list.

PHP Api - Results/Array question

I have been looking around for PHP tutorials and I found a very detailed one that have been useful to me.
But now, I have a question. The results showed by the API are stored into a $results array. This is the code (for instance):
$fetch = mysql_fetch_row($go);
$return = Array($fetch[0],$fetch[1]);
$results = Array(
'news' => Array (
'id' => $return[0],
'title' => $return[1]
));
My question is.. I want to display the last 10 news.. how do I do this? On normal PHP / mySQL it can be done as:
while($var = mysql_fetch_array($table)) {
echo "do something"
}
How can I make it so the $results can print multiple results?
I have tried like:
while($var = mysql_fetch_array($table)) {
$results = Array(
'news' => Array (
'id' => $return[0],
'title' => $return[1]
));
}
But this only shows me one result. If I change the $results .= Array(...) it gives error.
What can I do?
Thanks!
Edit
My function to read it doesn't read when I put it the suggested way:
function write(XMLWriter $xml, $data){
foreach($data as $key => $value){
if(is_array($value)){
$xml->startElement($key);
write($xml, $value);
$xml->endElement();
continue;
}
$xml->writeElement($key, $value);
}
}
write($xml, $results);
$results[] = Array(
'news' => Array (
'id' => $return[0],
'title' => $return[1]
));
That should do it.
If you are familiar with arrays, this is the equivalent of an array_push();
array_push() treats array as a stack, and pushes the passed variables onto the end of array. The length of array increases by the number of variables pushed. Has the same effect as:
<?php
$array[] = $var;
?>
Use [] to add elements to an array:
$results = array();
while($var = mysql_fetch_array($table)) {
$results[] = Array(
'news' => Array (
'id' => $var[0],
'title' => $var[1]
));
}
}
You can then loop through the $results array. It's not an optimal structure but you should get the hang of it with this.

Categories