Elasticsearch : Java Sprint Boot : Mapping results to clases - spring-boot

I am receiving the following error and not sure why. The error also shows me I am not getting the _id returned either.
{
"timestamp": "2018-10-28T09:45:26.129+0000",
"status": 500,
"error": "Internal Server Error",
"message": "failed to map source [ {\"meta_description\":\"Harry ollectables gifts\",\"body\":\"About us sDesign:\",\"title\":\"Harry Potter-Harry Potter nyl\",\"meta_keywords\":\"Harry Potter,\"}] to class Result",
"path": "/search/harry%20potter" }
So in kibana(Elasticsearch) if I query the data it looks like:
{
"_index": "burf",
"_type": "pages",
"_id": "https://www.ebay.ca/sns",
"_score": 15.293041,
"_source": {
"meta_description": "With nearly one million Stores on eBay, you're sure to find your version of perfect.",
"body": "Skip to main ",
"title": "Search eBay Stores | eBay",
"meta_keywords": ""
}
},
My model in Spring Boot looks like:
#org.springframework.data.elasticsearch.annotations.Document(indexName = "burf", type = "pages")
data class Result(#Id val id: String,
val title: String,
val body: String,
val meta_description: String?,
val meta_keywords: String?) {
}

So finding another example: the following model fixed this, however, I still can't get the score?
#Document(indexName = "burf", type = "pages")
class Result {
#Id
var id: String? = null
var score: Float = 0.0f
var title: String? = null
var body: String? = null
var meta_description: String? = null
var meta_keywords: String? = null
}

Related

Spring mongo aggregate nested elements null

I have 3 collections: attributes, products and product_attributes. I am trying to retrieve product attributes with aggregation with nested attribute and product in it. But product and attribute always null
service method:
fun findById(id: String): Mono<ProductAttribute> {
val idField = "_id"
val productId = "productId"
val attributeId = "attributeId"
val attributesDb = "attributes"
val productsDb = "products"
val attributeName = "attribute"
val productName = "product"
fun lookup(from: String, localField: String, name: String) = LookupOperation.newLookup()
.from(from)
.localField(localField)
.foreignField(idField)
.`as`(name)
fun match(id: String) = Aggregation.match(Criteria.where(idField).`is`(ObjectId(id)))
fun unwind(field: String) = Aggregation.unwind(field)
val aggregation = Aggregation.newAggregation(
match(id),
lookup(productsDb, productId, productName),
unwind(productName),
lookup(attributesDb, attributeId, attributeName),
unwind(attributeName)
).withOptions(AggregationOptions.builder().allowDiskUse(true).build())
return operations.aggregate(aggregation, "product_attributes", ProductAttribute::class.java)
.last()
.doOnError { throwable -> logger.error("Failed to get productAttribute", throwable) }
}
ProductAttribute.kt
#Document(collection = "product_attributes")
data class ProductAttribute(
#Id
#JsonProperty("_id")
val id: String? = ObjectId().toHexString(),
#get:Transient #Value("null") val product: Product?,
#get:Transient #Value("null") val attribute: Attribute?,
val attributeId: String,
val productId: String,
val name: String,
val quantity: Int,
val photos: List<String>
) : Serializable
Response:
{
"data": {
"productAttributeId": {
"id": "62a3bff787418b6f837e9150",
"product": null,
"attribute": null,
"name": "string",
"quantity": 1,
"photos": [
"string"
]
}
}
}
As a workaround I have ended up with this result:
I made aggregate method with generic type. It will aggregate to Any type and then map to my specific type.
inline fun <reified T> aggregate(
aggregation: Aggregation,
collectionName: String,
operations: ReactiveMongoOperations,
objectMapper: ObjectMapper
): Flux<T> =
operations.aggregate(aggregation, collectionName, Any::class.java)
.map { data -> objectMapper.convertValue(data, T::class.java) }
I think there is a way to implement custom converter. I will think about this later. I will update answer on success

perform nested query in Python Graphene with distinct types in schema

I have the following data structure coming from a database:
[
{
'time': '2019-07-19T12:57:17Z',
'bizLocation': 'urn:epc:id:sgln:bizLocation.Company.3',
'city': 'dallas',
'countryCode': 'US',
'humid': 49,
'sID': '40:61:32:22:11:00',
'site': 'factory',
'stype': 'BME280',
'temp': 22.941
}
]
I wish to create a GraphQL API to query the Database and provide the query in the following output:
[
{
sID: String (same as sID),
sType: String (same as sType),
bizLocation: String (same as bizLocation),
values: [
{
timestamp: Datetime (same as time),
value: Float (value of 'temp')
mType: 'temp'
},
{
timestamp: Datetime (same as time),
value: Float (value of 'humid'),
mType: 'humid'
}
]
}
]
I am using Graphene to just test if it might work. Currently I am just playing around with the idea and tried to make the following GraphQL Schema:
type SensorDoc {
sID: String
sType: String
bizLocation: String
values: [SensorData]
}
type SensorData {
timestamp: String
value: Float
mType: String
}
Translated to Graphene is as follows:
import graphene
class SensorData(graphene.ObjectType):
timestamp = graphene.DateTime()
value = graphene.Float()
mType = graphene.String()
class SensorDoc(graphene.ObjectType):
sId = graphene.String()
sType = graphene.String()
bizLocation = graphene.String()
values = graphene.List(SensorData)
class Query(graphene.ObjectType):
sensor_data = graphene.List(SensorDoc)
def resolve_sensor_data(self, info):
# DB Query Logic Here!!
output = [] # output to return
for each_point in list_result:
SensorDoc(sId=each_point['sID'], sType=each_point['stype'],
bizLocation=each_point['bizLocation'],
SensorData(timestamp=each_point['time'],
value=each_point['humid'], mType='humid') # <---- This is a SyntaxError
)
output.append(SensorDoc)
return output
This wouldn't work since SensorData won't pass as keyword argument.
I am completely new to trying out Graphene and was wondering how is this achievable when the query should look like the following:
query{
sensorData {
sID
sType
bizLocation
values {
timestamp
value
}
}
}
I was able to solve this issue by resolving the values within the SensorDoc class as follows:
class SensorData(graphene.ObjectType):
timestamp = graphene.String()
temp = graphene.Float()
humid = graphene.Float()
class SensorDoc(graphene.ObjectType):
sId = graphene.String()
sType = graphene.String()
bizLocation = graphene.String()
values = graphene.List(SensorData)
def resolve_values(parent, info):
# DB Query Logic
output = [] # output to return
for each_point in list_result:
output.append(
SensorData(timestamp=each_point['time'], temp=each_point['temp'], humid=each_point['humid'])
)
return output
And Within the main Query Class, kept the resolve_sensor_doc resolver:
class Query(graphene.ObjectType):
sensor_doc = graphene.List(SensorDoc)
def resolve_sensor_doc(self, info):
# DB Query Logic
output = []
for each_point in list_result:
output.append(
SensorDoc(
sId=each_point['sID'],
sType=each_point['stype'],
bizLocation=each_point['bizLocation']
)
)
return output
Finally the execution:
schema = graphene.Schema(query=Query)
result = schema.execute(
'''
query {
sensorDoc{
sId
sType
bizLocation
values {
timestamp
temp
humid
}
}
}
'''
)
items = dict(result.data.items())
print(json.dumps(items, indent=4))
Provides me the the output as follows:
{
"sensorDoc": [
{
"sId": "60:64:05:9C:DF:F2",
"sType": "BME280",
"bizLocation": "urn:epc:id:sgln:bizLocation.3",
"values": [
{
"timestamp": "2019-07-19T12:57:17Z",
"temp": 22.941,
"humid": 49.0
},
{
"timestamp": "2019-07-19T12:57:19Z",
"temp": 22.981,
"humid": 47.0
},
{
"timestamp": "2019-07-19T12:57:21Z",
"temp": 23.001,
"humid": 47.0
}
]
},
{
"sId": "60:64:05:9C:DF:F2",
"sType": "BME280",
"bizLocation": "urn:epc:id:sgln:bizLocation.3",
"values": [
{
"timestamp": "2019-07-19T12:57:17Z",
"temp": 22.941,
"humid": 49.0
},
{
"timestamp": "2019-07-19T12:57:19Z",
"temp": 22.981,
"humid": 47.0
},
{
"timestamp": "2019-07-19T12:57:21Z",
"temp": 23.001,
"humid": 47.0
}
]
},
{
"sId": "60:64:05:9C:DF:F2",
"sType": "BME280",
"bizLocation": "urn:epc:id:sgln:bizLocation.3",
"values": [
{
"timestamp": "2019-07-19T12:57:17Z",
"temp": 22.941,
"humid": 49.0
},
{
"timestamp": "2019-07-19T12:57:19Z",
"temp": 22.981,
"humid": 47.0
},
{
"timestamp": "2019-07-19T12:57:21Z",
"temp": 23.001,
"humid": 47.0
}
]
}
]
}

Filtering a dynamo db table yields Invalid KeyConditionExpression GSI

I have a table that contains an id and a name, I have a GSI index with the partition key theName and the sort column Last_attended . I'm trying to query it using a Lambda but I'm not able to return any results. I keep getting errors around the formatting. I'm using the DocumentClient with the query method, it just keep giving me a different error every time I run it.
Not sure what I'm missing here, any help is appreciated.....
!-- data
{
"id": 20919382411,
"Belt_awarded": "green",
},
{
"id": 20919382412,
"Belt_awarded": "yellow",
}
!--- code
const docClient = new AWS.DynamoDB.DocumentClient()
const params = {
TableName : `students`,
"IndexName": "theName-Last_attended-index",
KeyConditionExpression: '#id = :id_val',
ExpressionAttributeValues: { ":id_val": {"N": "20919382411"}, ':v_name': { 'S': 'joe' } }
}
Where is your ExpressionAttributeNames ?
You defined #id as expression attribute but you don't declare any ExpressionAttributeNames
You are using document client. It should be something like this
const params = {
TableName: 'students',
IndexName: 'Belt_awarded-index',
KeyConditionExpression: '#Belt_awarded = :Belt_awarded',
ExpressionAttributeNames: {
'#Belt_awarded': 'Belt_awarded'
},
ExpressionAttributeValues: {
':Belt_awarded': 'yellow'
},
};

AWS appsync w/ Lambd function backend, GraphQL gives unexpected repsonce to Query

What follows is all in the AWS console. My lambda function defines deletePost
case "deletePost":
var id = event.arguments.id;
callback(null, {id:-1,author:"me",title:"title"}); //note, regardless of what your args are right now it is returning id:-1
break;
My schema is
type Mutation {
...
deletePost(id: ID!): Post!
}
type Post {
id: ID!
author: String!
title: String
}
and my graphiQL query is
mutation DeletePost{
deletePost(id: 3){
id
}
}
For some reason it just parrots id=3 back to me when i've hard coded id as -1? If I ask for author or title to be return in my query I don't get them back at all.
Update full lambs fxn. Just a slightly modified version of the template that is provided with the aws appSync docs.
exports.handler = (event, context, callback) => {
console.log("Received event {}", JSON.stringify(event, 3));
var posts = { //in memory array store (simulates DB)
"1": {"id": "1", "title": "First book", "author": "Author1"},
"2": {"id": "2", "title": "Second book", "author": "Author2"},
"3": {"id": "3", "title": "Third book", "author": "Author3"},
"4": {"id": "4", "title": "Fourth book", "author": "Author4"},
"5": {"id": "5", "title": "Fifth book", "author": "Author5"} };
console.log("Got an Invoke Request: "+event.field);
switch(event.field) {
case "getPost":
var id = event.arguments.id;
callback(null, posts[id]);
break;
case "updatePost":
posts[event.arguments.id]=event.arguments;
console.log(posts);
callback(null, event.arguments);
break;
case "deletePost":
var id = event.arguments.id;
//delete posts[event.arguments.id];
callback(null, {id:-1,author:"me",title:"tits"});
break;
case "allPosts":
var values = [];
for(var d in posts){
values.push(posts[d]);
}
callback(null, values);
break;
case "addPost":
var id = event.arguments.id;
posts[id]=event.arguments;
console.log(posts);
callback(null, event.arguments);
break;
case "addPostErrorWithData":
var id = event.arguments.id;
var result = posts[id];
// attached additional error information to the post
result.errorMessage = 'Error with the mutation, data has changed';
result.errorType = 'MUTATION_ERROR';
callback(null, result);
break;
default:
callback("Unknown field, unable to resolve" + event.field, null);
break;
}
};
Resolvers. For the most part just pass the data straight through.
#request mapping
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": {
"field": "addPost",
"arguments": $util.toJson($context.arguments)
}
}
#responce mapping
$util.toJson($context.result)
It's hard to know without seeing all of the Lambda function and also your resolver templates. From the above code I'm going to guess you used this tutorial as a starting point: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html
Assuming you're passing back the result in the response template, like $util.toJson($context.result), then the issue is most likely with the structure of the callback in your Lambda function
let result = {"id" :-1, "author":"me", "title":"title"}
callback(null, result);
Essentially you need to pass back a result object for it to be seen in the $context object and converted as a GraphQL JSON response to the caller.

How to assign a single object to a list?

I'm working with an API rest and it returns me two types of json, object and array.
Object(When there is only one record in the database):
{ "complain": { "id": "1" , "description": "hello", "date": "2017-01-24 11:46:22", "Lat": "20.5204446", "Long": "-100.8249097" } }
Array(When there is more than one record in the database):
{ "complain": [ { "id": "1" , "description": "hello", "date": "2017-01-24 11:46:22", "Lat": "20.587446", "Long": "-100.8246490" }, { "id": "2" , "description": "hello 2", "date": "2017-01-24 11:50:12", "Lat": "20.529876", "Long": "-100.8249097" } ] }
The code I use to consume the json is as follows:
content = await response.Content.ReadAsStringAsync();
var token = JToken.Parse(content);
if (token["complain"] is JArray)
{
var jsonArray = JsonConvert.DeserializeObject<RootArray>(content);
}
else if (token["complain"] is JObject)
{
var jsonObject = JsonConvert.DeserializeObject<RootObject>(content);
}
When it comes to a json array if I can add it to a listview:
myList.ItemsSource = jsonArray.listArray;
But if it is an object I can not and I get the following error:
Cannot implicitly convert type Object to IEnumerable.
Finally I was able to solve my error, it was just a matter of creating a list and adding the deserialized json object.
var jsonObject = JsonConvert.DeserializeObject<RootObject>(content);
List<Complain> simpleList = new List<Complain>();
simpleList.Add(jsonObject.ComplainObject);
myList.ItemsSource = simpleList;
The class to deserialize the Json object:
public class RootObject
{
[JsonProperty("complain")]
public Complain ComplainObject { get; set; }
}

Resources