I've been reading the documentation and other example posts since yesterday to work out how to add sort by field and the direction to my current query array here but so far no luck. I've seen examples like {"sort": {"_score": "desc"}, "query": { .... but couldn't quiet get my head around it to modify my array since this is the very first time I'm dealing with ES.
All I need is: I want to be able to sort by price or stock in asc or desc order.
Everytime I try to update my array to implement sorting, I get {"error":{"code":0,"message":"Invalid option sort"}} error.
NOTE: The query array is being passed to Pagerfanta to get results.
$paginator = $this->productFinder->findPaginated($myArray)
->setMaxPerPage($limit)
->setCurrentPage($page);
Here's an example:
{
"_source":true,
"query":{
"simple_query_string":{
"query":"1*"
}
},
"sort":[
{
"price":{
"order":"desc",
"missing":"_last"
}
},
{
"_score":{
"order":"desc",
"missing":"_last"
}
}
]
}
For the specific field and direction:
{
"sort": {
"price": "asc"
}
... rest of the code
}
For no particular sorting (this is set by default):
{
"sort": {
"_score": "desc"
}
... rest of the code
}
Related
I'm using ES 6.6 and I'm doing a search for documents that are older than the current date. There are only 2 documents, but I get 3 items returned. The 2 existing documents and the third, are the settings and mappings. I only want to get the two documents.
I tried to add a filter with "exists", but then ES not return any document:
GET _search
{
"query": {
"bool": {
"filter": [
{
"exists": {
"field": "products"
}
},
{
"range": {
"happening_at": {
"gte": "now"
}
}
}
]
}
}
}
When I search only with the range, I receive the 2 correct documents, but with extra "hit" without document, only with settings and mappings.
Welcome to SO, Adrián.
You are firing a _search across all indices since you've not specified any index name. Please try GET <your_index_name>/_search { ... request body ...}.
Also, "gte": "now" will hardly return any records since it means date greater than or equal to current date. In your case, you want records older than current date. So you could use lt:now or better still lt:now/d since now/d is good in terms of performance and allows caching.
Try the below:
GET <your_index_name>/_search
{
"query": {
"bool": {
"filter": [
{
"exists": {
"field": "products"
}
},
{
"range": {
"happening_at": {
"lt": "now/d"
}
}
}
]
}
}
}
You have to POST your query :). If you want make a get please dont forget the /.
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html
I am in a problem of modifying the cake association hierarchy,I am new to cakephp , below is the snippet of code.
Current Code
$this->Cateogory->find('all');
The output of the above expression is of the below form :
[
{
"Category": {
"id": "37",
"title": "Inner Title",
"color": "#ffffff",
"phone-number": ""
},
"CategoryHas": [],
"PhoneNumberhas": []
}
]
Requirement :-
I am creating API for third party consumption , now the third party has given the output format as below. I want the the output to be of below form.
[
{
"Category": {
"id": "37",
"title": "Inner Title",
"color": "#ffffff",
"phone-number": "",
"CategoryHas": [],
"PhoneNumberhas": []
}
}
]
I am searching on this problem for past 1 day and I consider that I need to make a custom PHP function to solve the problem.
Thanks in advance :
Just use a loop
To convert the array of the first format to an array of the second format - just use a loop e.g.:
foreach ($stuff as &$row) {
$row['Category']['CategoryHas'] = $row['CategoryHas'];
$row['Category']['PhoneNumberhas'] = $row['PhoneNumberhas'];
unset($row['CategoryHas'], $row['PhoneNumberhas']);
}
This would be appropriate to put in your controller if it's only needed in one place.
If you always, always want your results in that format, use an afterFind method (or a behavior) to implement the same logic:
// In the category model
public function afterFind($results, $primary = false) {
foreach ($results as &$row) {
if (isset($row['CategoryHas'])) {
$row['Category']['CategoryHas'] = $row['CategoryHas'];
}
if (isset($row['PhoneNumberhas'])) {
$row['Category']['PhoneNumberhas'] = $row['PhoneNumberhas'];
}
unset($row['CategoryHas'], $row['PhoneNumberhas']);
}
return $results;
}
Be wary of choosing this option - it means that your models act unconventionally, potentially meaning plugins don't work and other developers (or you, tomorrow) are confused by the way the models act.
Your association names are pretty strange. Why are they not better named? You can use proper names internally and reformat it when sending it.
If this is just about getting the API response into a silly format that doesn't provide additional benefit use JSON views and change the structure of the array in the view as needed. This section of the book explains it in detail, read it. Example taken from the book:
// Controller code
class CategoriesController extends AppController {
public function index() {
// ... get the categories
$this->set(compact('categories'));
}
}
// View code - app/View/Posts/json/index.ctp
foreach ($categories &$row) {
if (isset($row['CategoryHas'])) {
$row['Category']['CategoryHas'] = $row['CategoryHas'];
}
if (isset($row['PhoneNumberhas'])) {
$row['Category']['PhoneNumberhas'] = $row['PhoneNumberhas'];
}
unset($row['CategoryHas'], $row['PhoneNumberhas']);
}
echo json_encode(compact('categories'));
I would convince the client and bring some arguments for a proper response format and structure. Most clients usually don't know what they want. Sometimes you have smart asses who think they need something specific but can explain why. Check JSend or http://jsonapi.org/ on how to implement a proper API response format. Understand the reasons for these formats and bring these arguments to the client.
I am trying to write a query to search for a products on two columns called category1 and category2. I am working using elastic search php client and tried with match should query but this giving me wrong results because of match of substring.
But i am looking for exact match with OR operation on two columns. I am new to this please guide me.
$params['index'] = 'furnit';
$params['type'] = 'products';
$params['body']['query']['bool']['should'] = array(
array('match' => array('category1' => $category->name)),
array('match' => array('category2' => $category->name)),
);
$results = $this->elasticsearch->search($params);
If you are not searching then using a bool query in this scenario is not the right way to do it in elasticsearch. Queries are used when you are searching something and relevancy of your search keyword and score of matching documents matters.
Here you can apply a bool filter of elasticsearch to filter out the desired results. Using filters with queries (filtered query) is right way to do it as it excludes all non-matching documents and then you can search for desired documents by using match queries.
here's an example of a bool filter
{
"from": 0,
"size": 50,
"sort": [
{
"name" : {
"order": "asc"
}
}
],
"query": {
"filtered": {
"query": {
"match_all" : {}
},
"filter": {
"bool": {
"should": [
{
"term": {
"category1" : "category1"
}
},
{
"term": {
"category2" : "category2"
}
}
]
}
}
}
}
}
you can refer to docs as well (https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html)
Maybe your problem is you have used default analyzer (which is standard analyzer).
could you give me your mapping ?
I suggest you to change to use not_analyzer when indexing and use term filter/query.
You could use put mapping here to setting for your analyzer: Put Mapping
Edit: I have created a gist for you, check it here:
Mappings & Terms Filter
I have indexed a document in ElasticSearch that contains arrays like this:
{
"student": "John",
"sport": "Soccer",
"match":
{
"eventType": "League",
"date": "2013-12-31T11:00:00.000Z"
}
}
I need to perform a query that searches for, for example, all league matches (ie, where doc["match"]["eventType"] == "League")
I am using the ElasticSearch-PHP api 1.1.0 and tried querying as such as this without success:
$params['body']['query']['match']['match']['eventType'] = 'League';
I also tried:
$params['body']['query']['match']['match']->eventType = 'League';
What is the correct way to do such a search? The documentation has no such examples.
Can you convert this JSON to php object?
{
"query": {
"match": {
"match.eventType": "League"
}
}
}
I think this will do the work.
As a first step, try to use a different name for your soccer 'match' and call it 'game' to prevent causing a collision with the use of the 'match' operation.
I am trying to create some report filters where the user can search for profiles using any fields on the report. For example: search for any profile with firstname that starts with ann and grade that starts with vi etc.
Here is a query I have written so far:
{
from: 20,
size: 20,
query: {
filtered: {
query: {
match_all: [ ]
},
filter: {
bool: {
must: [
{
prefix: {
firstname: "ann"
}
},
{
prefix: {
grade: "vi"
}
}
]
}
}
}
},
sort: {
grade: {
order: "asc"
}
}
}
If I remove one child of must (in the bool filter), it works. But it doesn't return any results once I use more than one filters and I need to be able to use any number of entries in there.
Also, if I use should instead of must, it works. I'm not sure if I'm misunderstanding the logic, but to my understanding (in this case) must should return ONLY results with firstname that starts with ann and grade that starts with vi.
They do exist, but this query just doesn't find them.
Am I missing something here?
Thanks
Since, I cannot post comments yet. I'm answering with some assumptions.
First of all, I'm using ES 0.90.2 version and your query works fine for my inputs. However, depending on your input size and the platform that you executed your query, my answer may not be the right one.
Assumption: Number of data in the index is less than 20.
I've added following inputs to my index:
'{"name": "ann", "grade": "vi"}'
'{"name": "ann", "grade": "ii"}'
'{"name": "johan", "grade": "vi"}'
'{"name": "johan", "grade": "ii"}'
And my test query was the same as yours, and here is the result:
"hits" : {
"total" : 2,
"max_score" : null,
"hits" : [ ] // <-- see this part is blank
}
As you can see, it didn't listed hits, but there are two hits. That's because of the from:20 code segment. If you change that value, you can see some results. If you want to see all results just delete that part.
Note: Well if this is not the case, sorry for bothering :(