using elasticsearch query on springboot - java

I have this query working, I have the expected results using it in kibana.
GET my_index/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_shape" : {
"SitePoint" : {
"shape": {
"type": "polygon",
"coordinates" : [
[[18.85491,-33.92305],
[18.8604,-33.9319],
[18.85618,-33.9399],
[18.84809,-33.94153],
[18.85491,-33.92305]]
]
},
"relation": "within"
}
}
}
}
}
}
and I'm trying to build something solid using ElasticsearchRepository with Kotlin or Java, I really don't find much about it on the internet or I don't understand the documentation as I should.
val coor = mutableListOf(org.locationtech.jts.geom.Coordinate(18.85491,-33.92305),
org.locationtech.jts.geom.Coordinate(18.8604,-33.9319),
org.locationtech.jts.geom.Coordinate(18.85618,-33.9399),
org.locationtech.jts.geom.Coordinate(18.84809,-33.94153),
org.locationtech.jts.geom.Coordinate(18.85491,-33.92305))
val query = QueryBuilders
.geoShapeQuery("objects", ShapeBuilders.newPolygon(coor))
.relation(ShapeRelation.WITHIN)
just running this to see the query i have a java.lang.ClassNotFoundException: org.locationtech.spatial4j.exception.InvalidShapeException
Can someone help me?

after a bit of research this way I can use Spring's JPA to query
val filter = QueryBuilders.geoShapeQuery("SitePoint", ShapeBuilders.newPolygon(coordinates)).relation(ShapeRelation.WITHIN)
val searchQuery = NativeSearchQueryBuilder()
.withQuery(matchQuery("id", id))
.withFilter(filter)
.build()
return template.queryForList(searchQuery, MyClass::class.java)

Related

Spring Mongo Aggregation Project Filter

I'm having an issue implementing a Filter on a Projection that I have working in the Mongo Shell. I've got a Census object that contains a list of Employees.
{
"_id": "ID",
"name": "census1",
"employees": [ {
"eeId": "EE_ID1"
},
{
"eeId": "EE_ID2"
},
{
"eeId": "EE_ID3"
}
}
Realistically this could contain a lot of employees. So I'd like to be able to retrieve the main Census object, and a subset of employees. I've already implemented 'slice', so this is going to be retrieving a set of employees by their eeId.
This works fine:
db.census.aggregate(
[
{
$match: {
"_id": ObjectId("ID1")
}
},
{
$project: {
"censusName": 1,
"employees" : {
$filter : {
input: "$employees",
as: "employees",
cond: { $in: [ "$$employees.eeId", ["EE_ID1", "EE_ID3"]] }
}
}
}
}
]
).toArray()
The problem is, I can't get it implemented in Java. Here 'employeeIds' is a String of the IDs I want.
MatchOperation matchCensusIdStage = Aggregation.match(new Criteria("id").is(censusId));
ProjectionOperation projectStage = Aggregation.project("censusName")
.and(Filter.filter("employees")
.as("employees")
.by(In.arrayOf(employeeIds).containsValue("employees.eeId")))
.as("employees");
Aggregation aggregation = Aggregation.newAggregation(matchCensusIdStage, projectStage);
return mongoTemplate.aggregate(aggregation, Census.class, Census.class).getMappedResults().get(0);
For this, no results are returned. I've also tried implementing it with a BasicDBObject but got stuck there too.
EDIT (workaround):
I did get a solution using aggregation but not with the filter on the project. This is what I did:
db.parCensus.aggregate(
// Pipeline
[
{
$match: {
"_id": ObjectId("ID1")
}
},
{
$project: {
"_id": 0, "employee": "$employees"
}
},
{
$unwind: "$employee"
},
{
$match: {
"employee.eeId": { $in: ["EE_ID1", "EE_ID3"] }
}
}
]
).toArray()
Java Code:
MatchOperation matchCensusIdStage = Aggregation.match(new Criteria("id").is(censusId));
ProjectionOperation projectStage = Aggregation.project("censusName").and("employees").as("employee");
UnwindOperation unwindStage = Aggregation.unwind("employee");
MatchOperation matchEmployeeIdsStage = Aggregation.match(new Criteria("employee.eeId").in(employeeIds));
Aggregation aggregation = Aggregation.newAggregation(matchCensusIdStage, projectStage, unwindStage, matchEmployeeIdsStage);
I know I could add a $group at the end to put it back into one Census object, but I just created a separate CensusEmployee object to store it all.
The aggregation query posted in the question post works fine. The MongoDB Spring Data API for the aggregation ArrayOperators.In syntax is not clear. I couldn't implement a solution based on this aggregation (and no answers related to on the net).
But, the alternative solution is based on the following aggregation query - and it works fine.
db.collection.aggregate( [
{ $unwind: "$employees" },
{ $match: { "employees.eeId": { $in: ["EE_ID1", "EE_ID3"] } } },
{ $group: { _id: "$_id", name: { $first: "$name" }, employees: { $push: "$employees" } } }
] )
The Java code:
List<String> empsToMatch = Arrays.asList("EE_ID1", "EE_ID3");
MongoOperations mongoOps = new MongoTemplate(MongoClients.create(), "test");
Aggregation agg = newAggregation(
unwind("employees"),
match(Criteria.where("employees.eeId").in(empsToMatch )),
group("_id")
.first("name").as("name")
.push("employees").as("employees")
);
AggregationResults<Document> results = mongoOps.aggregate(agg, "collection", Document.class);

How to implement Stemmer search in Elasticsearch 6.1 on java

I need to implement stemmer search, I've found this link on elasticsearch documentation. There is json that I've had send to elascticsearch server. But I new in elasticsearch and cannot figure out how to implements this in java. I cannot also find any examples. Ccould you please help me with this?
I've add setting with
PUT /data
{
"settings": {
"analysis" : {
"analyzer" : {
"my_analyzer" : {
"tokenizer" : "standard",
"filter" : ["standard", "lowercase", "my_stemmer"]
}
},
"filter" : {
"my_stemmer" : {
"type" : "stemmer",
"name" : "english"
}
}
}
}
}
after that I am trying to find 'skis' with query:
GET data/_search
{
"query": {
"simple_query_string": {
"fields": [ "value36" ],
"query": "ski"
}
}
}
but result is empty

Operation with inner array attributes using Aggregation on Spring Data MongoDB

I have the following aggregation working on mongodb, but I not figured out how to replicate it on Spring Data.
db.pedido.aggregate( [
{ $unwind: "$items" },
{ $project: { itemValue: { $multiply: [ "$items.price", "$items.quantity"] } } },
{ $group: { _id: "$_id", orderValue: { $sum: "$itemValue" } } },
{ $match: { orderValue: { $gte: 150 } } }
] )
I've tried something like this,
Aggregation agg = Aggregation.newAggregation(Order.class,
project("items"),
unwind("items"),
project("items.price", "items.quantity").and("items.price").multiply("items.quantity").as("itemValue"),
group("_id").sum("itemValue").as("orderValue"),
match(where("orderValue").gte(150))
);
return operations.aggregate(agg, Order.class, Order.class).getMappedResults();
but I got the java.lang.IllegalArgumentException: Invalid reference 'price'! What's wrong in the Spring Aggregation? There is any way to use the mongodb aggregation with #Query methods, or so other way to do this?
I am using MongoDB 3.2 and spring-data-mongodb 1.9.1.RELEASE

Elasticsearch: Filter Query not working

I've been working to change my query to a filter in Elasticsearch using the java api. I've made sure that the fields I am running searches on are set to "not_analzed".
Here is the java code for the filter:
FilterBuilder andFilter = FilterBuilders.andFilter(FilterBuilders.termFilter("thread_name", keyword), FilterBuilders.termFilter("site_name", "test_site"));
QueryBuilder filteredQuery = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), andFilter);
SearchResponse threadResponse = client.prepareSearch("thread_and_messages").setQuery(filteredQuery).setSize(20).setFrom(firstRowOffset).execute().actionGet();
This then gets translated to this in JSON:
"filtered" : {
"query" : {
"match_all" : { }
},
"filter" : {
"and" : {
"filters" : [ {
"term" : {
"thread_name" : "apple"
}
}, {
"term" : {
"site_name" : "test_site"
}
} ]
}
}
}
When I try to do any searches it won't return the document I'm looking for which is thread_name: Apple and site_name: test_site.
Also when I run this using a curl command it won't find that document either.
Can anyone see what I'm doing wrong here?
You can use must clause.That will perform and operation
"query": {
"bool": {
"must": [
{
"query_string": {
"default_field": "thread_name",
"query": "apple"
}
},
{
"query_string": {
"default_field": "site_name",
"query": "test_site"
}
}
]
}
}

Elasticsearch java top level query

I am trying to run a search on the following json using the java api
{
"query": {
"has_child": {
"query" : {
"filtered": {
"query": { "match_all": {}},
"filter" : {
"and": {"filters":[
{"term": {"term": "value"}}
]}
}
}
},
"child_type": "child"
}
}
}
Here is the java code I have,
QueryBuilders.hasChildQuery("child", QueryBuilders
.filteredQuery(QueryBuilders.matchAllQuery(),
FilterBuilders.andFilter(FilterBuilders.
termFilter("term", "value"))));
However this just produces the json
{"has_child":
{"query":
{"filtered":
{"query":{"match_all":{}},
"filter":{
"and":
{"filters":[
{"term":{"term":"value"}}
]
}
}
}
},
"child_type":"child"
}
}
As you can see I am missing a top level { "query" : ... } but I cannot find out how to add this top level query using the java api for elasticsearch.
From my understanding inside the code
client.prepareSearch("parent-child")
.setSearchType(SearchType.QUERY_THEN_FETCH)
.setQuery(query)
.setFrom(0).setSize(60).setExplain(true)
.execute()
.actionGet();
It autowraps the query with {"query" : ...}
My issue was that I was searching on the wrong index.

Categories

Resources