Elasticsearch Not Exist Value - sql

I was working on a query that I found. It's a little bit more complex than I thought. This is part of each data document which is distinguished by an event name.
"eventTime" : "2021-07-11T08:29:00-0800",
"userId" : "P9QuPERPURPC3swJpyBb4",
"eventName" : "mko", // mko and mkp are two possible values
"eventData" : {}
The target is: userIds who have eventName('mko') AND does not have eventName('mkp')
I could not precisely understand what is the best way to handle 'not exist' in Elasticsearch queries. I'd appreciate any help.

I think the below queries might help you.
Get a user with the name mko:
{
"query": {
"bool": {
"must": [
{
"term": {
"eventName": "mko"
}
}
]
}
}
}
Get a user with a name other than mko:
{
"query": {
"bool": {
"must_not": [
{
"term": {
"eventName": "mko"
}
}
]
}
}
}
Get a user with the name mkp:
{
"query": {
"bool": {
"must": [
{
"term": {
"eventName": "mkp"
}
}
]
}
}
}
Get a user with a name other than mkp:
{
"query": {
"bool": {
"must_not": [
{
"term": {
"eventName": "mkp"
}
}
]
}
}
}
To get the selected fields only you can use the _source field in query: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html.
And to check whether the field eventName is exists in a document. You can use the exists query within the must queries: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html

Related

Query item in nested array

Customer appointments with top level locationId sample data set:
[
{
"locationId": 9999,
"customerAppointments": [
{
"customerId": "1",
"appointments": [
{
"appointmentId": "cbbce566-da59-42c2-8845-53976ba63d56",
"locationName": "Sullivan St"
},
{
"appointmentId": "5f09e2af-ddae-47aa-9f7c-fd1001a9c5e6",
"locationName": "Oak St"
}
]
},
{
"customerId": "2",
"appointments": [
{
"appointmentId": "964a3c1c-ccec-4082-99e2-65795352ba79",
"locationName": "Kellet St"
}
]
},
{
"customerId": "3",
"appointments": []
}
]
},
{
...
},
{
...
}
]
I need to pull out appointment by locationId and customerId and only get the appointment for that customerId e.g
Sample response:
[
{
"appointmentId": "964a3c1c-ccec-4082-99e2-65795352ba79",
"locationName": "Kellet St"
}
]
Tried below query, but it just returns all records for all customers ids (which is kind of expected):
db.getCollection("appointments").find(
{
"locationId" : NumberInt(9999),
"customerAppointments" : {
"$elemMatch" : {
"customerId" : "2"
}
}
}
);
But how can I get just the appointment record for a specific customerId?
When asking this question I was unaware of the older version of MongoDB driver (< v5) so we cannot use the $getField operator.
However, this query seems to work well:
db.getCollection("appointments").aggregate([
{
$match: {
"locationId": NumberInt(9999)
}
},
{
$unwind: "$customerAppointments"
},
{
$match: {
"customerAppointments.customerId": "2"
}
},
{
$project: {
appointments: "$customerAppointments.appointments"
}
}
]);
Yields:
{
"_id" : ObjectId("63eebe95c7a0da54804c1db2"),
"appointments" : [
{
"appointmentId" : "964a3c1c-ccec-4082-99e2-65795352ba79",
"locationName" : "Kellet St"
}
]
}

Convert a SQL query to the ElasticSearch query

I wrote this query in SQL and now I needed it in the elastic search.
How can I do that?
select * from listings where condition1 = true or (condition2 = 1 and condition3 = false)
Here you go:
POST listings/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"condition1": {
"value": "true"
}
}
},
{
"bool": {
"must": [
{
"term": {
"condition2": {
"value": "1"
}
}
},
{
"term": {
"condition3": {
"value": "false"
}
}
}
]
}
}
]
}
}
}
You need to use should clause for or and must clause for and.
You need to use term or match query based on your requirement.

I have written mysql query wanted to convert same in elastic search query

'''select count(*) as count from activity where project_id in (61,129) and (entry_device_id in (1068,1069) or exit_device_id in (1068,1069) );'''
I tried with should in elastic query and match but not getting the desired results.
Got some idea from elasticsearch bool query combine must with OR
And tried but not getting the correct results.
Need help in this
Depending on your index's mapping, a combination of terms queries should get you started:
GET your_activity_index/_count
{
"query": {
"bool": {
"must": [
{
"terms": {
"project_id": [ 61, 129 ]
}
},
{
"bool": {
"should": [
{
"terms": {
"entry_device_id": [ 1068, 1069 ]
}
},
{
"terms": {
"exit_device_id": [ 1068, 1069 ]
}
}
]
}
}
]
}
}
}

Elasticsearch: Update mapping field type ID from long to string

I changed the elasticsearch mapping field type from:
"articles": {
"properties": {
"id": {
"type": "long"
}}}
to
"articles": {
"properties": {
"id": {
"type": "string",
"index": "not_analyzed"
}
After that I did the following steps:
Create the index with new mapping
Reindex the mapping to the new index
After the mapping update my previous query filter doesn't work anymore and I have no results:
GET /art/_search
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"type": {
"value": "articles"
}
},
{
"term": {
"id": "123467679"
}
}
]
}
}
}
},
"size": 1,
"sort": [
{
"_score": "desc"
}
]
}
If I check with this query the result is what I expect:
GET /art/articles/_search
{
"query": {
"match_all": {}
}
}
I would appreciate if somebody have some idea why after the field type change the query is no longer working.
Thanks!
The problem in the query was with ID filter.
The query works correctly changing the filter from:
"term": {
"id": "123467679"
}
in:
"term": {
"_id": "123467679"
}
I'm still a beginner with elasticsearch to figure out why the mapping change broke the query although I did the reindex, but "_id" fixed my query.
You can find more informations in the :
elasticsearch mapping reference documentation.

ElasticSearch:filtering documents based on field length?

Is there a way to filter ElasticSearch documents based on the length of a specific field?
For instance, I have a bunch of documents with the field "body", and I only want to return results where the number of characters in body is > 1000. Is there a way to do this in ES without having to add an extra column with the length in the index?
Use the script filter, like this:
"filtered" : {
"query" : {
...
},
"filter" : {
"script" : {
"script" : "doc['body'].length > 1000"
}
}
}
EDIT
Sorry, meant to reference the query DSL guide on script filters
You can also create a custom tokenizer and use it in a multifields property as in the following:
PUT test_index
{
"settings": {
"analysis": {
"analyzer": {
"character_analyzer": {
"type": "custom",
"tokenizer": "character_tokenizer"
}
},
"tokenizer": {
"character_tokenizer": {
"type": "nGram",
"min_gram": 1,
"max_gram": 1
}
}
}
},
"mappings": {
"person": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
},
"words_count": {
"type": "token_count",
"analyzer": "standard"
},
"length": {
"type": "token_count",
"analyzer": "character_analyzer"
}
}
}
}
}
}
}
PUT test_index/person/1
{
"name": "John Smith"
}
PUT test_index/person/2
{
"name": "Rachel Alice Williams"
}
GET test_index/person/_search
{
"query": {
"term": {
"name.length": 10
}
}
}