I am trying to convert MySQL search criteria to Eleasticsearch (version 7) query, however, both queries (MySQL and Elasticsearch) gives different results. On the SQL statement, it shows a single record, and on Elasticsearch, it shows 0 records. Any help or guidance is much appreciated on this.
SQL criteria
COUNT(*) WHERE (document_title like '%never listened%' or document_content like '%never listened%') and documnent_tone = 'negative'
Converting to Elasticsearch - using PHP Elasticsearch library
use Elasticsearch\ClientBuilder;
...
$elasticServer = $this->getOption('elasticsearch')->getElasticServer1();
$hosts = array(
$elasticServer['host'] . ':' . $elasticServer['port']
);
$client = ClientBuilder::create()
->setHosts($hosts)
->build();
$params = array (
"index" => "index_politics",
"body" => array(
"query" => array(
"bool" => array(
"must" => array(
array(
"wildcard" => array(
"document_title" => "never listened",
)
),
array(
"wildcard" => array(
"document_content" => "never listened"
)
),
array(
"match" => array(
"document_tone" => "negative"
)
)
)
)
)
)
);
$response = $client->count($params);
$negative = $response['count'];
var_dump($negative);
After much digging, the following worked for me
use Elasticsearch\ClientBuilder;
...
$elasticServer = $this->getOption('elasticsearch')->getElasticServer1();
$hosts = array(
$elasticServer['host'] . ':' . $elasticServer['port']
);
$client = ClientBuilder::create()
->setHosts($hosts)
->build();
$params = array (
"index" => "index_politics",
"body" => array(
"query" => array(
"bool" => array(
"must" => array(
array(
"multi_match" => array(
"query" => "never listened",
"fields" => array("document_title", "document_content")
)
)
),
"filter" => array(
"term" => array(
"document_tone" => "negative"
)
)
)
)
)
);
$response = $client->count($params);
$negative = $response['count'];
var_dump($negative);
Converted to Elasticsearch query
GET /index_politics/_count
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "never listened",
"fields": [
"document_title",
"document_content"
]
}
}
],
"filter": {
"term": {
"document_tone": "negative"
}
}
}
}
}
Related
Appreciate your time!
After reviewing several 'Compare and Merge' threads, finally, I am going to request someone to help with this very specific scenario.
$input = array(
[ 2616 ] => array(
[ 9878767654 ] => array(
[ 987987987 ] => 987987987,
[ 987987986 ] => 987987986,
),
),
[ 2618 ] => array(
[ 9878767654 ] => array(
[ 987987987 ] => 987987987,
),
),
[ 'tmp-9878767654' ] => array(
[ 9878767654 ] => array(
[ 987987985 ] => 987987985,
[ 987987987 ] => 987987987,
),
),
[ 'tmp-9878767655' ] => array(
[ 9878767655 ] => array(
[ 987987975 ] => 987987975,
),
),
);
$desired_output = array(
[ 2616 ] => array(
[ 9878767654 ] => array(
[ 987987987 ] => 987987987,
[ 987987986 ] => 987987986,
[ 987987985 ] => 987987985,
),
),
[ 2618 ] => array(
[ 9878767654 ] => array(
[ 987987987 ] => 987987987,
[ 987987986 ] => 987987986,
[ 987987985 ] => 987987985,
),
),
[ 'tmp-9878767655' ] => array(
[ 9878767655 ] => array(
[ 987987975 ] => 987987975,
),
),
);
This is the inventory of products (listed by Product ID and Model ID) by Store ID. I want to merge the Model ID values WHERE the product id is the same FROM the array with store-ID starting with 'tmp-'. If product ID is not matched then I want that array to stay as it is. I hope I am making some sense.
Please help.
Here is a snippet to solve the specific problem posed by your example:
$temporaryStores = [];
$prefix = 'tmp-';
$prefixLength = strlen($prefix);
// extract the temporary store structures
foreach ($input as $storeId => $store) {
if (is_string($storeId) && strpos($storeId, $prefix) === 0) {
$productId = (int) substr($storeId, $prefixLength);
$temporaryStores[$productId] = $store;
unset($input[$storeId]);
}
}
// merge matching temporary store structures into the actual ones
$mergedProductIds = [];
foreach ($temporaryStores as $temporaryProductId => $temporaryModels) {
$temporaryModels = reset($temporaryModels); // Incompatible array structure
foreach ($input as $storeId => $store) {
foreach ($store as $productId => $models) {
if ($productId === $temporaryProductId) {
$modelsIds = array_merge($temporaryModels, $models);
$modelsIds = array_unique($modelsIds);
$input[$storeId][$productId] = $modelsIds;
$mergedProductIds[] = $temporaryProductId;
unset($temporaryStores[$temporaryProductId]);
}
}
}
}
// append leftover temporary store structures to the result
foreach ($temporaryStores as $temporaryProductId => $temporaryModels) {
if (!in_array($temporaryProductId, $mergedProductIds, true)) {
$input[$prefix . $temporaryProductId] = $temporaryModels;
}
}
var_dump($input);
This snippet might work for you or not. Either way, I strongly suggest you refactor this code into using a more object oriented design. Where it is made obvious what each value/structure represents, and validation can occur in isolation.
Now you are left having to deal with incompatible array structures that visually look like an incomprehensible mess.
I wrote a mongodb query that I am having a hard time converting to php code:
var geoips = db.geoip.find().map(function(like){ return like.ip; });
var result = db.audit.aggregate([
{ $match: { ip: { $nin: geoips } } },
{ $group: {
_id: "$ip",
count: { $sum: 1 }
}}
]);
UPDATE:
The above query is the equivalent of the following Relation Database Query
Select ip,count(*)
from audit
where ip not in (select ip from geoip)
group by ip
Since I had to make this query in mongodb version 3.0, I was unable to take advantage of $lookup as suggested in an answer.
The below PHP code accomplishes the above objective and works as expected. It gets the distinct ips from geoip collection. It passes that result and does an aggregate on the audit collection to get the desired result.
$geoipcolln = $this->dbConn->selectCollection('geoip');
$geoips = $geoipcolln->distinct('ip');
$match = array('ip' => array('$nin' => $geoips));
$result = $this->collection->aggregate(
array(
'$match' => $match
),
array('$group' => array(
'_id' => '$ip',
'count' => array('$sum' => 1.0),
))
);
This can be done in one aggregation query using the $lookup operator as follows:
var result = db.audit.aggregate([
{
"$lookup": {
"from": "geoip",
"localField": "ip",
"foreignField": "ip",
"as": "geoips"
}
},
{ "$match": { "geoips.0": { "$exists": false } } },
{ "$group": {
"_id": "$ip",
"count": { "$sum": 1 }
}}
])
which can then be translated to PHP as:
<?php
$m = new MongoClient("localhost");
$c = $m->selectDB("yourDB")->selectCollection("audit");
$ops = array(
array(
"$lookup" => array(
"from" => "geoip",
"localField" => "ip",
"foreignField" => "ip",
"as" => "geoips"
)
),
array( "$match" => array( "geoips.0" => array( "$exists" => false ) ) ),
array( "$group" => array(
"_id" => "$ip",
"count" => array( "$sum" => 1 )
))
);
$results = $c->aggregate($ops);
var_dump($results);
?>
I've the following Aggregation:
$pipeline = array(
array('$match' => array(
'matchDate' => array(
'$lte' => $dateEnd, // DateTime object
'$gte' => $dateStart // DateTime object
)
)),
array('$group' => array(
'_id' => '$sport',
'count' => array('$sum' => 1)
))
);
$m = new \MongoClient('localhost');
$c = $m->selectDB('test_database')->selectCollection('Match');
$t = $c->aggregate($pipeline);
This aggregation will return an empty Result.
If I run the aggregation on my MongoDB directly, it works without problems and gives the expected results.
Here is the native query.
db.Match.runCommand({
"aggregate": "Match",
"pipeline": [
{
"$match": {
"matchDate": {
"$lte": new ISODate("2015-10-07T23:59:59+02:00"),
"$gte": new ISODate("2015-10-06T00:00:00+02:00")
}
}
},
{
"$group": { "_id": "$sport", "count": { "$sum": 1 } }
}
]});
The problem occurs only with aggregation. Find queries with date ($lte, $gte) works also without problems.
Here is an example document.
{
"_id": ObjectId("5613bbb79042ad801f0041ab"),
"sport": ObjectId("5613bbb79042ad801f0041a8"),
"matchDate": new Date("2015-09-26T13:45:00+0200")
}
Has someone an idea whats happen here?
I'm Using
MongoDB Support 1.6.11
PHP 5.6.13
MongoDB 3.0.6
It'll work with MongoDate.
$pipeline = array(
array('$match' => array(
'matchDate' => array(
'$lte' => new MongoDate($dateEnd->getTimestamp()),
'$gte' => new MongoDate($dateStart->getTimestamp())
)
)),
array('$group' => array(
'_id' => '$sport',
'count' => array('$sum' => 1)
))
);
$m = new \MongoClient('localhost');
$c = $m->selectDB('test_database')->selectCollection('Match');
$t = $c->aggregate($pipeline);
Thanks #Blakes Seven
I have this collection :
...
"votes": [
{
"track1": [
{
"facebook": NumberLong(1)
}
],
"track2": [
{
"google": NumberLong(1),
"twitter": NumberLong(1)
}
]
}
],
...
I want to get the sum of the votes of track1 or track2 so what i did is :
$match = array(
'app_id' => (int)$appId,
'campaign_id' => (int)$campaign_id
);
$group = array(
'_id' => 'votes.0.'.$_t.'.0.facebook', //$_t => track id
'total' => array(
'$sum' => '$votes.0.'.$_t.'.0.facebook'
)
);
$res = $collection->aggregate(array(
array(
'$match' => $match
),
array(
'$group' => $group
)
)
);
$res_facebook = (int) $res['result'][0]['total'];
Result : 0
Where is the problem ?
Not sure if it will work, I didn't check it, but I had something similar.
This is how I would solve it:
$votes_array = json_decode($votes_array_json,TRUE);
$total_votes = 0;
foreach($votes_array as $track) {
foreach($track as $social_network => $votes) {
$total_votes = $total_votes + $votes;
};
};
Current Code:
$doc = array('ooxx' => array(1,2,3,4,5));
datamodel()->insert($doc);
$doc2 = array('ooxx' => array(6,7,8,9));
datamodel()->insert($doc2);
$macher = array('ooxx'=>array('$exists' => true), 'ooxx' => array('$nin'=>array(6)));
$res = datamodel()->findOne($macher);
print_r($res);
When I replace the $macher with bellow, it does work well, why? is this a bug of mongodb?
$macher = array( 'ooxx' => array('$nin'=>array(6)), 'ooxx'=>array('$exists' => true));
It doesn't work because the keys have the same name and one overwrites the other. So the "keys" need to be unique.
If you have two conditions for the same key you use the $and operator which takes an array of arguments:
$matcher = array(
'$and' => array(
array( 'ooxx' => array( '$nin' => array(6) ) ),
array( 'ooxx' => array( '$exists' => true ) )
)
)
Or for the JSON minded:
{
"$and": [
{ "ooxx": { "$nin": [6] } },
{ "ooxx": { "$exists": true } }
]
}
Which is a valid structure where what you are writing is not.