How to construct nested query using criteria and criteriaQuery in spring-data-elasticsearch - spring-data-elasticsearch

I am using spring-data-elasticsearch. I have constructed most of the query conditions using criteria with lots of sub-criteria. Now I want to include a simple query condition for a nested field. But criteria corms query using uery_string API which is not working for nested fields. I am expecting Nested query.
How to support this using Criteria without NativeSearchQuery?
Nested Mapping
{
"ae": {
"type": "nested",
"properties": {
"atb": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"su": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
I want to query "ae.su.keyword" field. Building criteriaQuery using this field constructs query_string query using this field, which is not returing correct documents in response as expected. My expectationis, Is there any way to build nested query using criteria? or Override existing criteria query?
Criteria criteria = new Criteria("ae.su.keyword").is("VALUE");
CriteriaQuery query = new CriteriaQuery(criteria);
elasticOperations.search(query, Foo.class, index);

Currently Spring Data Elasticsearch's CriteriaQuery does not support creating nested queries.
The query that is created currently with your example code is (cleaning out irrelevant parts):
{
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "one",
"fields": [
"ae.su.keyword^1.0"
]
}
}
]
}
}
}
With the nested object you have the needed query would be:
{
"query": {
"nested": {
"path": "ae",
"query": {
"bool": {
"must": [
{
"query_string": {
"query": "one",
"fields": [
"ae.su.keyword"
]
}
}
]
}
}
}
}
}
basically wrapping the query that is built now in an additional nested query.
As I wrote, creating this nested query is not supported at the moment. What you can do, besides building a
NativeSearchQuery, is using a StringQuery (yes, it's very ugly as well):
Query query = new StringQuery("{\"nested\":{\"path\":\"ae\",#" +
"\"query\":{\"bool\":{\"must\":[{\"query_string\": {\"query\":\"$1\"," +
"\"fields\":[\"ae.su.keyword\"]}}]}}}}".replace("$1", value));
return operations.search(query, Foo.class);
Edit 01.04.2021:
This topic came up again in an issue, I opened a bug issue to address this. I will go to implement this fix these days.
Edit 05.04.2021:
fixed from 4.2.0.GA on

Related

Elasticsearch get results count of other indices with same query

I have a cluster setup with multiple indicies, generated from a rails server. Each index is a model in my server.
Looking to search a single index, but get counts for the other indices (models) based on my query json. Is this possible?
The query im using is generated from searchkick and quite large so I'm refraining from posting here. I'm trying to figure out if aggs does what I need, something like. I'd like to refrain from doing a 2nd query if possible
POST blog_index/_search
{
"query": { ... }
"aggs": {
"results_count": { ... }
}
}
=> What I would like to receive
{
"aggregations": {
"results_count": {
"blogs": 123,
"users": 234,
}
}
}
Example:
If do a { "term": { "type": "funny" } } on blog_index/_search, and there are 3 users with that type, I'd like to get that count as part of my blog_index query
Solution: You can aggregate on field _index.
"group_by_index": {
"terms": {
"field": "_index",
"size": "30"
}
}

Application Insights API $select not returning all results when values share part of path

I'm not sure if this is an OData issue or an Application Insights issue, but the App Insights API is not giving me all of the values I selected. It works normally most of the time, but when I ask for two values that share the beginning of their path, it only gives me the second value I asked for.
Here's an example of my issue:
data:
{
"count": 1,
"type": "customEvent",
"customDimensions": {
"success": "true",
"version": "ver-1"
},
"other": {
"key": "val-1"
}
},
{
"count": 2,
"type": "customEvent",
"customDimensions": {
"success": "false",
"version": "ver-2"
},
"other": {
"key": "val-2"
}
}
These all return the results that I'm expecting:
Query: $select=count,type
{
"count": 1,
"type": "customEvent"
},
{
"count": 2,
"type": "customEvent"
}
Query: select=customDimensions/success,other/key
{
"customDimensions": {
"success":"true"
},
"other": {
"key":"ver-1"
}
},
{
"customDimensions": {
"success":"false"
},
"other": {
"key":"ver-2"
}
}
However, if I try to get two values that start with the same path, it only shows me the second one.
Query: select=customDimensions/success,customDimensions/version
{
"customDimensions": {
"version":"ver-1"
}
},
{
"customDimensions": {
"version":"ver-2"
}
}
Is this an issue with either OData or Application Insights, or is there some other way I can format my query to give me the information I want? Thanks!
Update:
You can use the query api as following to fetch the data:
https://api.applicationinsights.io/v1/apps/Your_application_id/query?query=requests
| where timestamp >ago(5h)
| project customDimensions.UsersNamed, customDimensions.TenantsCoded
I test it in postman, see screenshot below:
Seems that your App Insights query is ok, I tested it using this .
I fetch the operation/name and operation/id(which starts with same path), original like this:
Then input some necessary condition, as screenshot below:
After click "Fetch" button, you can see the operation/name and operation/id are both returned.

Filtered search with Authorization for Elasticsearch

I'm trying to do a search where I look for "test" in any field while filtering for a specific client in the client_id field. Can't seem to figure this one out. This is how fat I got (but it's not working):
{
query: {
filtered: {
query: "test",
filter: {
term: {client_id: #client.id}
}
}
}
}
This is the right syntax
{
"query": {
"filtered": {
"query": {
"match": {
"_all": "test"
}
},
"filter": {
"term": {
"client_id": #client.id
}
}
}
}
}
From ES Docs: The _all field allows you to search for values in documents without knowing which field contains the value

How do I design a ruby equivalent objects for this json structure

I have a json structure that I need to build up based on url parameters provided by a client. Currently I've been building the json structure out using Jbuilder.encode but it's getting pretty hairy.
self.query = Jbuilder.encode do |json|
json.query do
json.filtered do
json.filter do
json.bool do
if(search_term && username)
json.array!(should) do
........
How can I build ruby objects so that I convert them into json based on how they are initialized?
Below is the full json structure I'd like to capture in ruby models/poros (plain old ruby objects).
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [
{
"query": {
"query_string": {
"query": "tablet",
"fields": [
"standard_analyzed_name",
"standard_analyzed_message"
]
}
}
},
{
"term": {
"username": "feedmatic"
}
}
],
"must": [
{
"terms": {
"status_type": [
"3",
"4"
]
}
},
{
"range": {
"created_on": {
"gte": 20140712,
"lte": 1405134711
}
}
}
]
}
}
}
}
}
Hmm i'm not really sure about Poro's, but one thing I've seen is that when the structure starts to get hairy is to make a method that returns the hash representation of what you would like to show. Have you tried making a query method that returns a hash with that structure and then calling it in a jbuilder template?
There's an .attributes method for rails that returns a hash with the attributes, but you would have to look into how to use it with a PORO and if it works for this purpose.

Filter result based on a count of inner data

I am building my search query for some listing data. As part of the search people can ask for multiple rooms which sleeps a min amount of people, ie two rooms which sleep 2 and 3 people.
Im not sure how I can perform that with a filter.
Here is a shortened search query so far.
{
"query":{
"filtered":{
"query":{
"match_all":{}
}
}
},
"filter":{
"and":
[
{
"term":{
"status":"live"
}
},
{
"geo_bounding_box":{
"location":{
"top_left":"60.856553, -8.64935719999994",
"bottom_right":"49.8669688, 1.76270959999999"
}
}
}
,{
"range":{
"bedrooms":{
"gte":"2"
}
}
}
]
}
,
"size":10
}
Test Data
{
"took":1,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"failed":0
},
"hits":{
"total":3,
"max_score":1.0,
"hits":[
{
"_index":"listings",
"_type":"listing",
"_id":"1",
"_score":1.0,
"_source":{
"name:":"Listing One",
"address1":"Some Street",
"bedrooms":2,
"city":"A City",
"id":1,
"refno":"FI451",
"user_id":1,
"rooms":[
{
"bathroom":"Shared bathroom with bath",
"double_standard":null,
"id":5,
"single":2,
"sleeps":2,
"title":"Twinny",
},
{
"bathroom":"Ensuite with bath",
"double_king_size":1,
"double_standard":1,
"id":1,
"single":null,
"sleeps":2,
"title":"Double Ensuite Room",
}
]
}
},
{
"_index":"listings",
"_type":"listing",
"_id":"2",
"_score":1.0,
"_source":{
"name":"Listing Two",
"address1":"Some Street",
"bedrooms":2,
"city":"A City",
"id":2,
"refno":"BL932",
"user_id":1,
"rooms":[
{
"bathroom":"Ensuite with bath",
"double_standard":1,
"id":4,
"single":1,
"sleeps":3,
"title":"Family Room",
},
{
"bathroom":"Ensuite with shower",
"double_standard":1,
"id":2,
"single":null,
"sleeps":2,
"title":"Single Room",
}
]
}
},
{
"_index":"listings",
"_type":"listing",
"_id":"3",
"_score":1.0,
"_source":{
"name":"Listing Three",
"address1":"Another Address",
"bedrooms":1,
"city":"Your City",
"id":3,
"refno":"TE2116",
"user_id":1,
"rooms":[
{
"bathroom":"Ensuite with shower",
"double_king_size":null,
"double_standard":1,
"id":3,
"single":1,
"sleeps":3,
"title":"Family Room",
}
]
}
}
]
}
}
If you look at my data I have 3 listings, two of them have multiple rooms (Listing One & Two) but only Listing Two would match my search, Reason it has one room with that sleeps two and the other sleeps three.
Is it possible to perform this query with elasticsearch?
If what you want is "Find all listings where a bedroom sleeps 2 AND another bedroom sleeps 3", this query will work. It makes one big assumptions: that you are using inner objects, and not the Nested data type.
This query is using the fact that inner objects are collapsed into a single field, causing "rooms.sleeps" to equal [2,3] for the desired field. Since the field is collapsed into a single array, a simple Terms query will match them. When you change the execution mode to And, it forces both 2 and 3 to be matched.
The caveat is that a room that has [2,3,4] will also be matched.
I've omitted the geo and status portion since that data wasn't provided in the source documents.
{
"query": {
"filtered": {
"query": {
"match_all": {}
}
}
},
"filter": {
"and": [
{
"range": {
"bedrooms": {
"gte": "2"
}
}
},
{
"terms": {
"rooms.sleeps": [2,3],
"execution": "and"
}
}
]
},
"size": 10
}
As far as I know the filter has to be a sibling of the query inside the filtered element. See: http://www.elasticsearch.org/guide/reference/query-dsl/filtered-query/
If you combine that with Zach's solution it should work.
{
"query":
{
"filtered":
{
"query":
{
"match_all":{}
},
"filter":
{
"put" : "your filter here"
}
}
}
}

Resources