ElasticSearch match query multiple terms PHP - php

I am trying to construct must query on multiple terms, the array looks like this:
$params = [
'body' => [
'query' => [
"bool" => [
"must" => [
"terms" => [
"categories" => [
"Seating",
],
],
"terms" => [
"attributes.Color" => [
"Black",
],
]
],
"filter" => [
"range" => [
"price" => [
"gte" => 39,
"lte" => 2999,
],
],
],
],
],
'from' => 0,
'size' => 3,
],
];
Which is represented in JSON like this:
{
"query": {
"bool": {
"must": {
"terms": {
"attributes.Color": ["Black"]
}
},
"filter": {
"range": {
"price": {
"gte": "39",
"lte": "2999"
}
}
}
}
},
"from": 0,
"size": 3
}
The problem is, JSON objects are represented as arrays in PHP so if I setup key for one array, it is rewritten. Do you have any idea on how to create multiple terms query in PHP?
Thanks in advance.

You need to add an additional array to enclose all your terms queries
$params = [
'body' => [
'query' => [
"bool" => [
"must" => [
[
"terms" => [
"categories" => [
"Seating",
],
]
],
[
"terms" => [
"attributes.Color" => [
"Black",
],
]
]
],
"filter" => [
"range" => [
"price" => [
"gte" => 39,
"lte" => 2999,
],
],
],
],
],
'from' => 0,
'size' => 3,
],
];

Related

How to use MDword to generate multi-level nested Office Word?

effect picture:
https://i.stack.imgur.com/f2r3O.png
github address:
https://github.com/mkdreams/MDword
data:
$arr = [
[
"title1" => "title1",
"meeting_content"=>[
[
"title11" => "title11,title11",
"content11" => "content,content,content,content,content,content,content,content,content,"
],
[
"title22" => "title22,title22",
"content22" => "content,content,content,content,content,content,content,content,content,"
],
],
"children" => []
],
[
"title" => "title",
"meeting_content"=>[
],
"children"=>[
[
"title1" => "title1",
"meeting_content"=>[
[
"title11" => "title11,title11",
"content11" => "content,content,content,content,content,content,content,content,content,"
],
[
"title22" => "title22,title22",
"content22" => "content,content,content,content,content,content,content,content,content,"
],
],
],
[
"title2" => "title2",
"meeting_content"=>[
[
"title11" => "title11,title11",
"content11" => "content,content,content,content,content,content,content,content,content,"
],
[
"title22" => "title22,title22",
"content22" => "content,content,content,content,content,content,content,content,content,"
],
],
],
],
],
];
How to use MDword to generate multi-level nested Office Word?
Now I need to, using a MDword extension of PHP, write this multidimensional data into a Word document, I don't know what to do, it has the effect picture, and Github address, thank you
You can use pstyle.You can see the demo.
Details as follows(You must update to the latest version):
data
$numDatas = [
[
'title'=>'title-1',
'content'=>'content-1'
],
[
'title'=>'title-2',
'sub'=>[
[
'title'=>'subTitle-2-1',
'content'=>'content-2-1',
],
[
'title'=>'subTitle-2-2',
'content'=>'content-2-2',
],
]
],
[
'title'=>'title-3',
'sub'=>[
[
'title'=>'subTitle-3-1',
'content'=>'content-3-1',
],
[
'title'=>'subTitle-3-2',
'content'=>'content-3-2',
],
]
],
];
temple IMG:
https://i.stack.imgur.com/dS1U1.png
code
$TemplateProcessor->cloneP('num',count($numDatas));
foreach($numDatas as $idx => $numData) {
$TemplateProcessor->cloneP('num'.'#'.$idx,3);
$TemplateProcessor->setValue('num'.'#'.$idx.'#0',[['text' => $numData['title'], 'pstyle' => 'numstyle-level-1', 'type' => MDWORD_TEXT]]);
if(isset($numData['content'])) {
$TemplateProcessor->setValue('num'.'#'.$idx.'#1',[['text' => $numData['content'], 'pstyle' => 'numstyle-level-3', 'type' => MDWORD_TEXT]]);
}else{
$TemplateProcessor->deleteP('num'.'#'.$idx.'#1');
}
$subName = 'num'.'#'.$idx.'#2';
if(isset($numData['sub'])) {
$TemplateProcessor->cloneP($subName,count($numData['sub']));
foreach($numData['sub'] as $subIdx => $subData) {
$TemplateProcessor->cloneP($subName.'#'.$subIdx,2);
$TemplateProcessor->setValue($subName.'#'.$subIdx.'#0',[['text' => $subData['title'], 'pstyle' => 'numstyle-level-2', 'type' => MDWORD_TEXT]]);
$TemplateProcessor->setValue($subName.'#'.$subIdx.'#1',[['text' => $subData['content'], 'pstyle' => 'numstyle-level-3', 'type' => MDWORD_TEXT]]);
}
}else{
$TemplateProcessor->deleteP($subName);
}
}
$TemplateProcessor->deleteP('numstyle');
result IMG:
https://i.stack.imgur.com/sb0MB.png

PHP ElasticSearch compound query with has_child

When I query Elasticsearch for products from a specific manufacturer, this works:
$params = ['index' => 'products',
'type' => 'product',
'body' => ['query' =>
['match' => ['manufacturers_id' => $query],],
],
];
But when I also want to add on a condition that the product comes in color Silver, which I have added as a child record to the product record, I get a syntax error:
$params = ['index' => 'products',
'type' => 'product',
'body' => ['query' =>
['match' => ['manufacturers_id' => $query],],
['query' =>
['has_child' =>
['type' => 'attributes',
['query' =>
['color' => 'Silver'],],
],
],
],
],
];
The error is
{
"error": {
"col": 49,
"line": 1,
"reason": "Unknown key for a START_OBJECT in [0].",
"root_cause": [
{
"col": 49,
"line": 1,
"reason": "Unknown key for a START_OBJECT in [0].",
"type": "parsing_exception"
}
],
"type": "parsing_exception"
},
"status": 400
}
Also tried
$params = ['index' => 'products',
'type' => 'product',
'body' => ["query"=> [
"match"=> [
"manufacturers_id"=> [11]
],
"has_child"=> [
"type"=> "attributes",
"query"=> [
"match"=> [
"color"=> "silver"
],
],
],
],
],
];
I get "Can't get text on a START_ARRAY at 1:39."
Try this:
"query"=> [
"match"=> [
"manufacturers_id"=> [1,2,3]
],
"has_child"=> [
"type"=> "attributes",
"query"=> [
"match"=> [
"color"=> "silver"
]
]
]
]
I also recommend Sense, it's a plugin for Chrome browser which helps writing ES queries.
See the screenshot
Finally got this to work. Big thanks to #pawle for his suggestion of Sense, which really helped.
$params = ['index' => 'products',
'type' => 'product',
'body' =>
[
"query" => [
"bool" => [
"must" => [[
"has_child" => [
"type" => "attributes",
"query" => [
"match" => [
"attributes_value" => "silver"
]
]
]
],
[
"match" => [
"manufacturers_id" => 4
]
]
]
]
]
],
];

elasticsearch return only one document of id field

I have this data returned with my actual query.
{
"id": 1,
"chantierId": 60,
"location": {
"lat": 49.508804203333,
"lon": 2.4385195366667
}
},
{
"id": 2,
"chantierId": 60,
"location": {
"lat": 49.508780168333,
"lon": 2.43844484
}
},
{
"id": 3,
"chantierId": 33,
"location": {
"lat": 49.50875823,
"lon": 2.4383772216667
}
}
This my Elasticsearch query which search the point with geo_point. :
[
"query" => [
"filtered" => [
"query" => [
"match_all" => []
],
"filter" => [
"geo_distance" => [
"distance" => "100m",
"location" => ['lat' => 49.508804203333, 'lon => 2.4385195366667]
]
]
]
],
"sort" => [
"_geo_distance" => [
"location" => ['lat' => 49.508804203333, 'lon => 2.4385195366667],
"order" => "asc"
]
]
]
How can I to have only one documents of chantierId for 33, 60 and the must nearest of my location.
Thanks
You can add size parameter before query as the number of documents you want to recieve. The modified query will be:
[ "size" => 1,
"query" => [
"filtered" => [
"query" => [
"match_all" => []
],
"filter" => [
"geo_distance" => [
"distance" => "100m",
"location" => ['lat' => 49.508804203333, 'lon => 2.4385195366667]
]
]
]
],
"sort" => [
"_geo_distance" => [
"location" => ['lat' => 49.508804203333, 'lon => 2.4385195366667],
"order" => "asc"
]
]
]
I Resolved my problem with this answer of stackoverflow question : Remove duplicate documents from a search in Elasticsearch
So :
[
"query" => [
"filtered" => [
"query" => [
"match_all" => []
],
"filter" => [
"geo_distance" => [
"distance" => "100m",
"location" => $location
]
]
]
],
"sort" => [
"_geo_distance" => [
"location" => $location,
"order" => "asc"
]
],
"aggs" => [
"Geoloc" => [
"terms" => [
"field" => "chantierId"
],
"aggs" => [
"Geoloc_docs" => [
"top_hits" => [
"size" => 1
]
]
]
]
]
]);
Thanks to #Tanu who tried to help me

Can't have a term and geo_distance_range in the same must filter

I have some data and I am trying to get all the results that have a certain month and are less than 1.6km from the target point. I am using the PHP client so my query looks like this.
$crimeSearch = [
'size' => 0,
'query' => [
'filtered' => [
'filter' => [
'bool' => [
'must' => [
'term' => [
'month' => $date,
],
'geo_distance_range' => [
'location' => [
'lat' => $lat,
'lon' => $lng,
],
'lt' => '1.6km',
],
],
],
],
],
],
'aggs' => [
'group_by_category' => [
'terms' => [
'field' => 'category',
],
],
],
];
I am currently seeing the following error:
query_parsing_exception: No query registered for [location]
My mapping looks like this:
"properties": {
"location": {
"type": "geo_point"
},
"category": {
"type": "string",
"index": "not_analyzed"
},
"month": {
"type": "string",
"index": "not_analyzed"
}
}
Now if I comment out either the term value or the geo_distance_range value from the must array then I get the correct results back. This error only occurs when they are both present.
Can anyone see what I wrong with my query?
I have tried moving the geo_distance_range into its own must block but this seems to bring back all results that match either of the the must filters and not them both.
If you need any more information please ask!
Thank you.
I do not know anything about PHP but If I try to convert equivalent ES json query then this might work. I guess you need to put every must clause in array like this
[
'size' => 0,
'query' => [
'filtered' => [
'filter' => [
'bool' => [
'must' => [
[
'term' => [
'month' => $date,
]
],
[
'geo_distance_range' => [
'location' => [
'lat' => $lat,
'lon' => $lng,
],
'lt' => '1.6km',
],
],
],
],
],
],
],
'aggs' => [
'group_by_category' => [
'terms' => [
'field' => 'category',
],
],
],
];
This is equivalent to
{
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"term": {
"month": "June"
}
},
{
"geo_distance_range": {
"lt": "1.6km",
"location": {
"lat": 37.9174,
"lon": -122.305
}
}
}
]
}
}
}
}
}
Does this work?

how to Improving relevancy in elasticsearch?

This is how my mapping looks
$arr = [
'index' => 'test1',
'body' => [
'settings' => [
'analysis' => [
'analyzer' => [
'name_analyzer' => [
'type' => 'custom',
'tokenizer' => 'standard',
'filter' => [
'lowercase',
'asciifolding',
'word_delimiter'
]
]
]
]
],
"mappings" => [
"info" => [
"properties" => [
"Name" => [// this field is analyzed
"type" => "string",
"fields" => [
"raw" => [ //subfield of Name is not analyzed so that we can avoid a known issue of space saperated bucket generation
"type" => "string",
"index" => "not_analyzed"
]
]
],
"Address" => [
"type" => "string",
"index" => "analyzed",
"analyzer" => "name_analyzer"
]
]
]
]
]
];
And this is my query
$query['index'] = 'test1';
$query['type'] = 'info';
//without bool & should also it will work
$query['body'] = [
'query'=> [
'bool' => [
'should' => [
'query_string' => [
'fields' => ['Name'],
'query' => 'sa*',
'analyze_wildcard' => 'true'
]
]
]
],
'size'=> '0',
'aggregations' => [
'actor' => [
'terms' => [
'field' => 'Name.raw',
'size' => 10
]
]
]
];
My output is
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"actor": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Salma Hayak",
"doc_count": 1
},
{
"key": "Salman Khan",
"doc_count": 1
},
{
"key": "Salman Shaikh",
"doc_count": 1
}
]
}
}
}
What I want is since Salman Khan is the most searched actor as compare to Salma Hayak, having said that when user searched for "sa" they should see salman khan first rather than salma hayak.
Can anyone please help me on this?

Categories