Combine OR, AND and IN operators in Elasticsearch query - php

I am very new to the elasticsearch and I need to prepare the query which combines OR, AND and IN operators.
What I want to achieve is having something like this in SQL:
SELECT * FROM tableWHERE (field_1 = 'foo' AND field_2 IN(1,2,3) ) OR ('field_1 = 'bar' AND field_2 IN(2, 3, 4) );
I am using elastic with PHP and have started with something like this:
'query' => [
'bool' => [
'should' => [
[
'match' => [
'field_1' => 'foo',
],
],
[
'match' => [
'field_1' => 'bar',
],
],
],
],
],
However, I cannot add query parameters to achive my desired result. Can you please help me with that?

You need to combine bool/must/should query clauses. For IN operator you can use terms query in elasticsearch
Try out this below query
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"match": {
"field_1": "foo"
}
},
{
"terms": {
"field_2": [
1,
2,
3
]
}
}
]
}
},
{
"bool": {
"must": [
{
"match": {
"field_1": "bar"
}
},
{
"terms": {
"field_2": [
2,
3,
4
]
}
}
]
}
}
]
}
}
}

Related

Subquery with NOT IN with MongoDB

I would like to create a query with mongodb which would do this thing:
SELECT * FROM Users WHERE Username NOT IN (SELECT LikeTo FROM Like WHERE Username = "John89").
i did something like this:
[
'$lookup'=> [
'from'=> "like",
'let'=> [ 'username'=> '$username' ],
'as'=> "leaders",
'pipeline'=> [
[
'$match'=> [
'$and'=> [
['$expr'=> [ '$not'=> ['$in'=> ['$likeTo','$$username']]]],
['username'=> "$username" ]
]
]
]
]
]
]
but i got PlanExecutor error during aggregation :: caused by :: $in requires an array as a second argument, found: string.
what did i do wrong? is the query right?
thanks!
I would personally split this into 2 queries, but here is how yo achieve this in a single pipeline, we actually want the lookup to match the "bad" users so we can use it to filter, like so:
db.users.aggregate([
{
"$lookup": {
"from": "likes",
let: {
username: "$username"
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$likeTo",
"$$username"
]
},
{
"$eq": [
"$username",
"John89"
]
}
]
}
}
}
],
"as": "leaders"
}
},
{
$match: {
"leaders.0": {
$exists: false
}
}
},
{
$project: {
leaders: 0
}
}
])
Mongo Playground

ElasticSearch PHP syntax

I'm new to ElasticSearch and don't really understand how the queries works...
My indexing example
{
"_index" : "indexing001",
"_type" : "_doc",
"_id" : "3",
"_version" : 1,
"_seq_no" : 242,
"_primary_term" : 2,
"found" : true,
"_source" : {
"type" : 1,
"sub_type" : null,
"user" : {
"id" : 1,
"name" : "tk6z2 gcnouvqmr"
},
"editor_user" : [ ],
"content" : [
{
"title" : "Title #3",
"short_text" : "Article #3 short text",
"full_text" : "Article #3 full text",
"locale" : "de-DE"
}
],
"flags" : [ ],
"location" : [ ],
"start_date" : 1658793600,
"end_date" : 1658793600,
"_users" : [ ]
}
}
I want to query the text to match the field content.title and content.short_text, query user by _users field.
For example my function is:
public static function search(
string $text = '',
int $user = 0
): array
{
try {
$model = new someModelClass();
$fields = [
'content.title',
'content.short_text',
];
$result = $model::find()->query( [
'bool' => [
'should' => [
'multi_match' => [
'query' => $text,
'fields' => $fields,
],
],
'filter' => [
[ 'term' => [ '_users.id' => $user ] ],
[ 'term' => [ '_users' => [] ] ],
]
],
] )->all();
return $result;
}
catch ( Exception $e ) {
throw new Exception( $e->getMessage() );
}
}
convert it to SQL it should be something like: SELECT * FROM 'indexing001' WHERE (content.title LIKE %search% OR content.short_text LIKE %search%) AND (users.id = 1 OR users = '')
How to write it in ElasticSearch query?
Thanks in advance!!
Well in that case i would recommend to use the Elasticsearch-PHP client.
Please install appropriate client using composer.
For a match query like below
curl -XGET 'localhost:9200/my_index/_search' -d '{
"query" : {
"match" : {
"testField" : "abc"
}
}
}'
You can make a query in your PHP Script like this
$params = [
'index' => 'my_index',
'body' => [
'query' => [
'match' => [
'testField' => 'abc'
]
]
]
];
$results = $client->search($params);
Check more operations here.
I'll try to reproduce your SQL and provide JSON query example, u will ez adapt it to PHP query method.
{
"query": {
"bool": {
"should": [
{"multi_match": {
"fields": ["content.title", "content.short_text"],
"query": "%query here%"
}}
],
"filter": {
"bool": {
"should": [
{"match": {"user.id": "%id here%"}},
{"match": {"user": []}},
]
}
}
}
}
}

How to deal with elasticsearch range Beetween 2 dates

I have the following mapping:
'contract' => [
'type' => 'nested',
'include_in_parent' => true,
'properties' => [
'started_at' => ['type' => 'date', 'format' => 'yyyy-MM-dd'],
'ended_at' => ['type' => 'date', 'format' => 'yyyy-MM-dd'],
],
],
I'm trying to write a query that searches for all active contracts; a contract is active when now is between started_at and anded_at, or started_at < now if the contract is undetermined (ended_at is null).
my try was the following, but still doesn't handle both the cases:
'bool' => [
'must' => [
['range' => ['applications.contract.started_at' => ['lte' => 'now']]],
['range' => ['applications.contract.ended_at' => ['gte' => 'now']]],
],
],
Any hint would be awesome, thanks folks!
When you have "nullable" field as "ended_at" you need to combine "range" and "must_not" into "should" because elasticsearch does not index NULL value (as a result it's a missing field)
So your query will look something like this:
{
"query": {
"bool": {
"must": [
{
"range": {"applications.contract.started_at": {"lte": "now"}}
},
"should": [
{
"range": {
"applications.contract.ended_at": {"gte": "now"}
}
},
{
"bool": {
"must_not": {
"exists": "applications.contract.ended_at"
}
}
}
]
}
}
}
also, I've noticed that you are using "nested" documents so the query above must be wrapped into a nested query
{
"bool": {
"must": {
"nested": {
"path": "contract",
"query": {
"bool": {
"must": [
{
"range": {"applications.contract.started_at": {"lte": "now"}}
}
],
"should": [
{
"range": {
"applications.contract.ended_at": {"gte": "now"}
}
},
{
"bool": {
"must_not": {
"exists": {"field": "applications.contract.ended_at"}
}
}
}
]
}
}
}
}
}
}

not able to get array in the correct shape

I am trying to create an elasticsearch query and for that I need to get my array in a particular shape but I am not able to get it.
desired output
"query": {
"bool": {
"must": {
"bool": {
"must": [
"match": {
"active": 1
},
"bool": {
"should": [
{
"match": {
"workspace_type.keyword": "lounge"
}
},
{
"match": {
"workspace_type.keyword": " cafe"
}
}
]
}
]
}
}
}
}
My source code
$query = [
'query' => [
'bool' => [
'must' => [
'bool' => [
'must' => []
]
]
]
]
];
$active_query = [
'match' => [
"active" => 1
]
];
$query['query']['bool']['must']['bool']['must'][] = $active_query;
$workspace_type_query = [
'match' => [
"workspace_type.keyword" => "lounge"
]
];
$workspace_type_object = (object) $workspace_type_query;
$query['query']['bool']['must']['bool']['must']['bool']['should'][] = $workspace_type_object;
only issue with this is I am not able to get must[] (the one above match and active ) and it was either coming as an indexed object like
{
"0": {
"match": {
"active": 1
}
}
}
or just an object like this
{
"match": {
"active": 1
}
}
but both these cases are not acceptable for the elasticsearch query that I am trying to generate .. any assistance would be highly appreciated.
I think the extra index that you create for must is wrong.
When you change it to
$query['query']['bool']['must']['bool']['must'] = $active_query;
it seems to work.
The result is
{
"query": {
"bool": {
"must": {
"bool": {
"must": {
"match": {
"active": 1
}
}
}
}
}
}
}

AND filter elastic search PHP

I'm trying to have multiple queries in ELASTIC SEARCH However I just want to have an operator AND to separate them as condition, for example as in SQL,
SELECT * FROM table where P=1 AND Q=2
In such query, we find only those results which will fulfil both conditions. In my case, P=1 is my first query and Q=2 is my second one.
How can I get the results for such query. Im using PHP.
Here's my Code:
// MY QUERY 1
$query["bool"]["must"][]["multi_match"] = array(
"query"=>$string,
"operator" => "and",
"fields" => array("firstname", "lastname")
);
// MY QUERY 2
$query["bool"]["must"][]["multi_match"] = array(
'query' =>$string2,
'fields' => array("firstname1", "firstname2")
);
// SEARCH
$return = $client->search(
array(
'index' => 'my_index',
'type' => 'typ',
'body' => array(
'query' => $query,
'size' => 100,
),
)
);
You can use a filter query with an and operator like this. Try it out.
{
"filter": {
"and": [
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "searchTerm1",
"fields": [
"firstname",
"lastname"
]
}
}
]
}
}
},
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "searchTerm2",
"fields": [
"firstname1",
"firstname2"
]
}
}
]
}
}
}
]
}
}

Categories