Spring data ElasticSearch #Query - elasticsearch

Im struggling building this query with the #Query annotation for spring-data:
{
"bool" : {
"must" : [
{
"query_string" : {
"query" : "123",
}
},
{
"bool" : {
"should" : [
{
"term" : {
"username" : {
"value" : "admin"
}
}
},
{
"terms" : {
"groups" : ["abc"],
}
}
],
}
}
]
}
}
I tried this:
#Query("{\"bool\": {\"must\": [{\"query_string\": {\"query\": \"?0\"}}, {\"bool\": { \"should\": [ {\"term\" : {\"username\" : \"?2\"}}, {\"terms\" : {\"groups\" : \"?1\"} } ] } } ] }}")
Page<Device> findByTermAndGroupOrUser(String term, List<String> groups, String username, Pageable pageable);
But it fails with:
ParsingException[[terms] query does not support [groups]]
Tried changing the query to:
#Query("{\"bool\": {\"must\": [{\"query_string\": {\"query\": \"?0\"}}, {\"bool\": { \"should\": [ {\"term\" : {\"username\" : \"?2\"}}, {\"terms\" : {\"groups\" : [\"?1\"]} } ] } } ] }}")
Page<Device> findByTermAndGroupOrUser(String term, List<String> groups, String username, Pageable pageable);
This works but the groups seem not to be evaluated. Documents containing the given group are not found.
Same query built with QueryBuilder like this works (but I´m missing the spring-data paging in this case)
BoolQueryBuilder qb = QueryBuilders.boolQuery();
QueryBuilder should1 = QueryBuilders.termQuery("username", username);
QueryBuilder should2 = QueryBuilders.termsQuery("groups", groups);
BoolQueryBuilder should = qb.should(should1).should(should2);
QueryStringQueryBuilder termQuery = QueryBuilders.queryStringQuery(term);
BoolQueryBuilder must = QueryBuilders.boolQuery().must(termQuery).must(should);
SearchResponse searchResponse = elasticsearchTemplate.getClient()
.prepareSearch()
.setQuery(must)
.setFrom(pageable.getPageNumber() * pageable.getPageSize())
.setSize(pageable.getPageSize())
.get();
What am I doing wrong?

Related

How to query elastic search with Hashmap

I would like to query the Elastic Search with map of values and retrieve the documents.
Example:
I have indexed the below two documents
1. {
"timestamp": 1601498048,
"props": {
"cp1": "cv1",
"cp2": "cv2"
}
}
2. {
"timestamp": 1601498098,
"props": {
"key1": "v1",
"key2": "v2"
}
}
So, I wanted to query with the entire map values props with
"props"
{
"cp1": "cv1",
"cp2": "cv2"
}
and return documents only for the entired matched map values. So in this case the result would be only first document, since it matched the given props.
I can able to query with only single map value like below , but need to search for entire map.
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"bool" : {
"must" : [
{
"terms" : {
"customProperties.cp1.keyword" : [ "cv1" ]
}
}
]
}
}
}
'
So how we query for entire map props and return documents only if all map key-values matched.
Update
Mainly I need a QueryBuilder to search with map of values. I could do for set of values like below
val sampleSet = setOf("foo", "bar")
val query = NativeSearchQueryBuilder()
.withQuery(
QueryBuilders.termsQuery(
"identifiers.endpointId.keyword", sampleSet)
)
.build()
I need QueryBuilder to search with map of values in the ES index and return document only if entire map values matches.
Suggestions please.
you must apply double match clausule.
{
"query": {
"bool": {
"must": [
{
"match": {
"props.cp1": "cv1"
}
},
{
"match": {
"props.cp2": "cv2"
}
}
]
}
}
}
Or Term.
{
"query": {
"bool": {
"must": [
{
"term": {
"props.cp1.keyword": "cv1"
}
},
{
"term": {
"props.cp2.keyword": "cv2"
}
}
]
}
}
}
This worked. I just looped through the queryBuilder with map values props.
val builder = QueryBuilders.boolQuery()
for (prop in props) {
builder.must(QueryBuilders.matchQuery("customProperties.${prop.key}", prop.value))
}
val query = NativeSearchQueryBuilder().withQuery(builder)
println("results + $queryForList(query)")
passed query to this function
internal fun queryForList(query: NativeSearchQuery): List<DocumentType> {
val resp = searchOperations.search(query, type, IndexCoordinates.of(indexName))
return resp.searchHits.map { it.content }
}

Mongodb query to Spring mongoTemplate

i have this mongo query:
db.getCollection('My_collection_name').aggregate([
{ $project: { warehouses: { $objectToArray: "$outputVariables" } } },
{ $unwind: "$warehouses" },
{ $group: { _id: "$warehouses.k" }}
])
someone could help me to translate in spring mongoTemplate?
Thanks
The query should be write as below:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
...
AggregationOperation project = project()
.and(ObjectToArray.valueOfToArray("outputVariables")).as("warehouses");
AggregationOperation unwind = unwind("warehouses");
AggregationOperation group = Aggregation.group("warehouses.k");
Aggregation aggregation = Aggregation.newAggregation(
project,
unwind,
group);
String collectionName = "My_collection_name";
System.out.println("aggregation=" + aggregation);
this.mongoTemplate.aggregate(aggregation, collectionName, Output.class);
It generate output:
aggregation={ "aggregate" : "__collection__", "pipeline" : [{ "$project" : { "warehouses" : { "$objectToArray" : "$outputVariables" } } }, { "$unwind" : "$warehouses" }, { "$group" : { "_id" : "$warehouses.k" } }] }

Unknown key for a START_OBJECT in [bool] in elastic search

Elasticsearch is giving this error like Unknown key for a START_OBJECT in [bool] in Elasticsearch.
My query is as below: Updated
var searchParams = {
index: 'offers',
body:{
query:{
bool : {
must : {
query: {
multi_match: {
query: query,
fields:['title','subTitle','address','description','tags','shopName'],
fuzziness : 'AUTO'
}
}
},
filter : {
geo_distance : {
distance : radius,
location : {
lat : latitude,
lon : longitude
}
}
}
}}},
filter_path :'hits.hits._source',
pretty:'true'
};
Can anyone tell me how to mix this both geo and fuzzy search query in elastic search?
The body should look like this (you're missing the query section):
body:{
query: { <--- add this
bool : {
must : {
multi_match: {
query: query,
fields:['title','subTitle','address','description','tags','shopName'],
fuzziness : 'AUTO'
}
},
filter : {
geo_distance : {
distance : radius,
location : {
lat : latitude,
lon : longitude
}
}
}
}}},

Spring Data Elasticsearch: Datas are stored in indexes despite "store" property is setted to false in #Field annotation

I'm making some tests with Spring Data Elasticsearch, Spring Boot, Spring Data Rest and an h2 Database (embedded).
I don't understand why the values are stored in the indexes despite I have this configuration:
#Entity
#Document(indexName = "computerindex", type="computers")
public class Computer {
#Id
#GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
private String id;
#Field(type=FieldType.String, store=false) private String name;
#Field(type=FieldType.String, store=false) private String brand;
}
#Configuration
#EnableWebMvc
#EnableJpaRepositories
#EnableElasticsearchRepositories
public class ElasticSearchConfig {
#Bean
public ElasticsearchTemplate elasticsearchTemplate() throws IOException {
return new ElasticsearchTemplate(getNodeClient());
}
private static NodeClient getNodeClient() throws IOException {
String pathHome = new File(".").getCanonicalPath();
NodeBuilder nodeBuilder = new NodeBuilder();
nodeBuilder
.settings()
.put("path.home", pathHome)
.put("path.logs", pathHome+"/logs");
return (NodeClient) nodeBuilder.clusterName("elasticsearch").local(true).node().client();
}
}
Going to the url http://localhost:8080/computers, initially there is an empty "_embedded" result (as expected):
{
"_embedded" : {
"computers" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/computers"
},
"profile" : {
"href" : "http://localhost:8080/profile/computers"
},
"search" : {
"href" : "http://localhost:8080/computers/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
When I save a new "Computer", I have this result:
{
"_embedded" : {
"computers" : [ {
"name" : "pc",
"brand" : "brand",
"_links" : {
"self" : {
"href" : "http://localhost:8080/computers/AVZZwpMlqIneBcTGH3av"
},
"computer" : {
"href" : "http://localhost:8080/computers/AVZZwpMlqIneBcTGH3av"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/computers"
},
"profile" : {
"href" : "http://localhost:8080/profile/computers"
},
"search" : {
"href" : "http://localhost:8080/computers/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
Now there is the interesting part.
If I stop the application and I restart it (without erase the indexes), since I have an embedded H2 database that runs and lives together with my application, I will expect that my "pc" is lost after that
the previous session has been terminated.
The indexes are also configured to not store any data.
When I restart the application, I still have this result:
"computers" : [ {
"name" : "pc",
"brand" : "brand",
"_links" : {
"self" : {
"href" : "http://localhost:8080/computers/AVZZwpMlqIneBcTGH3av"
},
"computer" : {
"href" : "http://localhost:8080/computers/AVZZwpMlqIneBcTGH3av"
}
}
The only explanation could be that the values are restored from the indexes: in fact, if I delete the indexes before restarting the application, I have an empty database (as I expect).
But I don't want to save the data in the indexes, and I don't want that the datas are pulled from the indexes.
Furthermore, I have explicitely configured store=false, and I didn't set the data(true) property (like this):
return (NodeClient) nodeBuilder.clusterName("elasticsearch").local(true).data(true).node().client();
Any ideas?

Elasticsearch: why Java client uses different query syntax?

I am new to Elasticsearch. I have the following query:
{
"query": {
"filtered" : {
"query" : {
"term" : {
"title" : "crime"
}
},
"filter" : {
"term" : { "year" : 1961 }
}
}
}
}
It runs fine under Windows prompt as follows:
curl -XGET localhost:9200/book/_search?pretty -d #my-query.json
For the same query with Java client, I have the following:
SearchResponse sr = client.prepareSearch("book")
.setTypes("fiction")
.setQuery(query_string)
.setFrom(page)
.setSize(10).execute().actionGet();
However, I have to the following query string in order to run it without exception:
{
"filtered" : {
"query" : {
"term" : {
"title" : "crime"
}
},
"filter" : {
"term" : { "year" : 1961 }
}
}
}
Why is there such a difference? How can I retain the removed "query" property"? Suppose that I have to use query string in my Java client.
Thanks and regards!
Strictly speaking, the two variants you show are not the same: you don't specify the type, offset, or size parameters in your URI-based query (even though you can do it there too, according to the docs). You can omit these parameters in Java query as well:
SearchResponse sr = client.prepareSearch("book")
.setQuery(query_string)
.execute().actionGet();
Regarding the argument for setQuery, it can be either the same JSON as you have in your URI variant:
String theQuery = String.join(System.getProperty("line.separator"),
"{\"filtered\" : {\"query\" : {\"term\" : {\"title\" : \"crime\"}},",
"\"filter\" : {\"term\" : { \"year\" : 1961 }}}}");
SearchResponse sr = client.prepareSearch("book")
.setTypes("fiction")
.setFrom(page)
.setQuery(queryString(theQuery)).execute().actionGet();
Or you can provide the analog of this query using Java methods:
SearchResponse sr = client.prepareSearch("book")
.setTypes("fiction")
.setFrom(page)
.setQuery(filteredQuery(QueryBuilders.termQuery("title","crime"),
FilterBuilders.termFilter("year","1961")))
.execute().actionGet();

Resources