am using elasticsearch in my Java Spring application, for working with elasticsearch Spring JPA is used.
I have a document and corresponding class in java with all fields that should not be indexed (I search through them for exact match using termFilter statement in java api)
In my case I have to annotate each field
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
and I get something like this
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonIgnoreProperties(ignoreUnknown = true)
#Document(indexName = "message", type = "message")
public class Message implements Serializable {
#Id
#NotNull
#JsonProperty("id")
private String id;
#JsonProperty("userName")
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String userName;
#NotNull
#JsonProperty("topic")
#Field(index = FieldIndex.not_analyzed, type = FieldType.String)
private String topic;
#NotNull
#JsonProperty("address")
#Field(index = FieldIndex.not_analyzed, type = FieldType.String)
private String address;
#NotNull
#JsonProperty("recipient")
#Field(index = FieldIndex.not_analyzed, type = FieldType.String)
private String recipient;
}
Is there a possibility to put annotation on class in order not to duplicate it above all fields?
You can achive your goal without #Field annotations using raw mappings + dynamic templates
Specify the path to your mappings in json file using #Mapping annotation
#Mapping(mappingPath = "/mappings.json")
Then in mappings.json define your mapping like this:
{
"mappings": {
"message": {
"dynamic_templates": [
{ "notanalyzed": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "string",
"index": "not_analyzed"
}
}
}
]
}
}
}
Note: I didn't test it, so please check for typos.
Related
I want to create some set of questions and answers
im able pass the code as json structure but it is not working as form data in postman so giving this following error or i don't know how to send the below code in the form-data anyone help me
{
"id": 1,
"title": "Html",
"description": "Hyper text markup language",
"category": "frontEnd",
"tag": "html",
"image": "html.jpg",
"questions": [
{
"question": "Where html belong to",
"optionA": "frontEnd",
"optionB": "backEnd",
"optionC": "database",
"optionD": "All the Above",
"answer": "frontEnd"
},
{
"question": "Where Java belong to",
"optionA": "frontEnd",
"optionB": "backEnd",
"optionC": "database",
"optionD": "All the Above",
"answer": "backEnd"
}
]
}
Im trying to pass like this ,click on this image to see postman
#RestController
#RequestMapping("student/blog")
public class BlogRestController {
#PostMapping(value = "/upload-files",consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
#ResponseBody
public ResponseEntity<Object> saveBlog(
#RequestPart("image") MultipartFile multipartFile,
#RequestParam("title") String title,
#RequestParam("description") String description,
#RequestParam("category") String category,
#RequestParam("tag") String tag,
#RequestParam("questions") List<Question> questions
)
throws IOException {
Blog blog = new Blog();
String fileName = StringUtils.cleanPath(multipartFile.getOriginalFilename());
blog.setImage(fileName);
blog.setTitle(title);
blog.setDescription(description);
blog.setCategory(category);
blog.setTag(tag);
blog.setQuestions(questions);
blogRepo.save(blog);
"Required request parameter 'questions' for method parameter type List is not present" error code but if I try to send it in this way
see this image
"message": "Failed to convert value of type 'java.lang.String' to required type 'java.util.List'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.dfsfe.entities.Question': no matching editors or conversion strategy found",
Here is My entity class
#Entity
#Table(name = "blog")
public class Blog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "title",nullable = false)
private String title;
#Column(name = "description",nullable = false,columnDefinition = "TEXT")
private String description;
#Column(name = "category",nullable = false)
private String category;
#Column(name = "tag",nullable = false)
private String tag;
#Column(name = "image",nullable = false)
private String image;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "questions",referencedColumnName = "id")
private List<Question> questions;
// with getters and setters
if anyone know please answer this question
I am working on validating the request body in Spring boot.
When the post controller using the below JSON to create record in the DB. It works fine.
{
"test1": "string",
"test2": "string",
"test3": "string", <--this has #Null in the entity
"test4": "string"
}
However, when one of the key is #NULL in the entity, it will still able to create a record in the DB. I am wondering if there is something that can validate the key and return error.
{
"test1": "string",
"test2": "string",
"test5": "string", <- wrong key by mistake
"test4": "string"
}
Entity class
#Entity
#Table(name = "test")
#Data
#NoArgsConstructor
public class Test implements Serializable {
#Id
#Column(name = "test1")
private String test1;
#Column(name = "test2")
#NotNull
private String test2;
#Column(name = "test3")
private String test3;
#Column(name = "test4")
private String test4;
}
You can use Jackson for parsing JSON and handle unknown properties. It will automatically throw UnrecognizedPropertyException if an unknown property is found as described here
If u want to Validate request body in JSON u can use #Valid
#PostMapping("/books")
Book newBook(#Valid #RequestBody Test test) {
return repository.save(Test);
}
#Column(name = "test3")
#NotNull(message = "Please provide a test3")
private String test3;
if u want on key order
JsonPropertyOrder({ "test1", "test2", "test3", "test4" })
public class Test implements Serializable {
}
I am trying to map an array of Objects to a field. All the fields in that object are being mapped to columns with different name but similar structure. The response structure should be:
"customers": [
{
"firstName": "string",
"lastName": "string",
"products": [
{
"description":"string",
"amount": "string"
},
{
"description":"string",
"amount": "string"
}
]
}
]
Inside the products field, I have a list of product(description and amount). In DB, columns are stored like
product_des1,product_amt1,product_des2,product_amt2.....product_des30,product_amt30
. I need to map these two fields to the product(object). How should I approach to solve the problem using JPA annotations if possible?
For the reference:
Customers.class
#Entity
public class Customers implements Serializable {
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#ElementCollection
List<Products> products;
}
Product.class
#Embeddable
public class Product implements Serializable {
#Column(?)
private String description;
#Column(?)
private String amount;
}
Inside the products field, I have a list of product(description and amount). In DB, columns are stored like
product_des1,product_amt1,product_des2,product_amt2.....product_des30,product_amt30
So your Products JPA entity should simply look like this:
#Embeddable
public class Products implements Serializable {
#Column(name = "product_des1")
private String description1;
#Column(name = "product_amt1")
private String amount1;
#Column(name = "product_des2")
private String description2;
#Column(name = "product_amt2")
private String amount2;
// ... repeat
}
if you don't want to do additional mapping between the DB and JPA entities (which I don't recommend - I try to keep JPA entities as exact representation of a DB row and map, if necessary, in Java and not between different technologies).
I have the following json that I would like to store it into java object:
{
"shippingDetails":{
"address":"khalda",
"country":"Jordan",
"town":"amman"
},
"product":[
{
"product":{
"id":2,
"name":"Wrap Dress",
"price":330,
"salePrice":165,
"discount":50,
"pictures":[
"assets/images/fashion/product/1.jpg",
"assets/images/fashion/product/1.jpg",
"assets/images/fashion/product/1.jpg",
"assets/images/fashion/product/1.jpg"
],
"shortDetails":"test",
"description":"test",
"stock":2,
"new":true,
"sale":false,
"category":"women",
"colors":[
"gray",
"orange"
],
"size":[
"M",
"L",
"XL"
],
"tags":[
"caprese",
"puma",
"lifestyle"
],
"variants":[
{
"color":"gray",
"images":"assets/images/fashion/product/1.jpg"
},
{
"color":"orange",
"images":"assets/images/fashion/product/1.jpg"
}
]
},
"quantity":1
}
],
"totalAmount":330
}
And I have the following java beans for it:
The main object class called Order and it has
#Data
#Entity
#Table(name = "orders")
public class Order {
#Id
#Column(name="shippingDetailsId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToOne(cascade = {CascadeType.ALL})
private ShippingDetails shippingDetails;
//#OneToMany(cascade = {CascadeType.ALL})
//List<Product> products;
List<Object> product = new ArrayList<>();
private float totalAmount;
}
and the inner object classes are:
#Data
#Entity
#Table(name = "products")
public class Product {
#Id
#Column(name = "productId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
private Order order;
private Boolean isNew;
private String salePrice;
private String shortDetails;
private String discount;
private String description;
private Variants[] variants;
private String[] pictures;
private String[] colors;
private String[] tags;
private String sale;
private String[] size;
private String price;
private String name;
private String stock;
private String category;
}
and the shipping details bean:
#Data
#Entity
#Table(name = "shippingDetails")
public class ShippingDetails {
#Id
#Column(name="shippingDetailsId")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String address;
private String country;
private String town;
}
I have tried many ways but non of them worked, first I have tried to accept an Order object in my controller and try to store it but did not work, the results were:
when using List all the values are printed to the console as desired and inserted in the database but in the same table Orders, that's not what I'm looking for, I want the Products to be saved in a separate table called Products so I used List.
when used List the values of the product were null.
Then I have tried to accept a string in from my controller and use GSON library to convert it to the Order object but it did not work as well, I got many kind of exceptions trying to figure it out and tried many ways that were mentioned on stackoverflow and other websites but no luck, please not that I have validated my json string and it is a valid json.
If you see the hierarchy in JSON it does not match your Java Object.
"product":[ // Parent-Product
{
"product":{ // Child-Product
"id":2,
A direct mapping to Java would be something like
List<Map<String,Product>> products
If you have the option to change the JSON file then change to something like below and get rid of the Parent-Child Product hierarchy.
"product":[
{
"id":..
},
{
"id":..
}
..
]
You can use the converter here. It generates java objects from json.
http://www.jsonschema2pojo.org/ (among others it supports, gson and jackson)
This will ensure that you have the correct mapping of Json to Java and vice versa.
I need information how to store the best way a Document (Java POJO) with the Spring-Data-Elasticsearch #Document Annotation which includes a Map
#Document(indexName = "downloadclienterrors", type = "downloadclienterror")
public class DownloadClientErrorLogElasticsearch {
#Id
private Long id;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String host;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String shortMessage;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String fullMessage;
#Field(type = FieldType.Date)
private String clientTimestamp;
private Integer level;
private Map<String, String> additionalFieldList;
...
}
Like the POJO is created in this 1st class I can store it via my repository in the elastic search instance.
This is the way how I add then data to it, I wanna be flexible which JSON fields I add, because that's flexible from my client software.
additionalFieldList.put("url", "http://www.google.de");
additionalFieldList.put("user_agent", "Browser/1.0.0 Windows");
My problem is that I need also the fields in the additionalFieldList marked as .not_analyzed. (f.e additionalFieldList.url, additionalFieldList.user_agent).
I would like to have the same behaviour like with the FieldIndex.not_analyzed annotation on a String also on my Map but of course only for the value in the map.
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private Map<String, String> additionalFieldList;
But that doesn't work when I try to store the document. I receive a ugly Exception.
When someone knows a way, or how it would be better to design such a document in elasticsearch, because I am quit fresh and new in this area I would love to hear some comments.
Thanks before and grey greetings from Hamburg,
Tommy Ziegler
You can use #Mapping annotation to configure dynamic_templates.
Just put your mapping file in your classpath and annotate your POJO with #Mapping
Mapping example
JSON
{
"downloadclienterrors": {
"dynamic_templates": [
{
"additionalFieldList": {
"path_match": "additionalFieldList.*",
"mapping": {
"type": "string",
"index": "not_analyzed"
}
}
}
]
...
}
}
POJO
#Mapping(mappingPath = "/downloadclienterrors.json")
#Document(indexName = "downloadclienterrors", type = "downloadclienterror")
public class DownloadClientErrorLogElasticsearch {
...
}
What you have to do is to create a another class additional and add additionalFieldList there.
something like this-
public class additional {
private Map<String, String> additionalFieldList;
}
and then use this class in your pojo
#Document(indexName = "downloadclienterrors", type = "downloadclienterror")
public class DownloadClientErrorLogElasticsearch {
#Id
private Long id;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String host;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String shortMessage;
#Field(type = FieldType.String, index = FieldIndex.not_analyzed)
private String fullMessage;
#Field(type = FieldType.Date)
private String clientTimestamp;
private Integer level;
#Field(type = FieldType.Nested)
private additional additional;
...
}