I am trying to make autocomplete suggestion using Elasticsearch. Here is my entity:
#Document(indexName = ESUtil.INDEX_NAME)
public class Person {
#Id
private String id;
#Field(type = FieldType.Text, name = "name")
private String name;
#Field(type = FieldType.Text, name = "surname")
private String surname;
#Field(type = FieldType.Integer, name = "age")
private int age;
#Field(type = FieldType.Text, name = "job")
private String job;
#CompletionField
private Completion suggest;
// getters-setters...
}
I am creating documents with this method:
#Autowired
private ElasticsearchRestTemplate elastic;
public String createOrUpdateDocument(Person person) {
IndexQuery query = new IndexQueryBuilder().withId(person.getId()).withObject(person).build();
return elastic.index(query, IndexCoordinates.of(ESUtil.INDEX_NAME));
}
And it is creating the index automatically with these config after create a document:
{
"dummy": {
"aliases": {},
"mappings": {
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"age": {
"type": "long"
},
"id": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"job": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"surname": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"settings": {
"index": {
"routing": {
"allocation": {
"include": {
"_tier_preference": "data_content"
}
}
},
"number_of_shards": "1",
"provided_name": "dummy",
"creation_date": "1674206424438",
"number_of_replicas": "1",
"uuid": "a_XWdCzxRUieyDZrioIaSg",
"version": {
"created": "8060099"
}
}
}
}
}
So my question is, where is my "suggest" field with "completion" type? I am using spring-data-elasticsearch (ver: 4.4.2), elasticsearch (ver: 8.6.0) and there is not any additional configuration.
Am I missing some config or should I create index by myself?
The mapping of an index is only created by Spring Data Elasticsearch when you are using Spring Data repositories:
during bootstrapping the repository support on application startup
(https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.repositories.autocreation).
So if you don't use repository access for your entities, or the index already exists, the mapping will not be written automatically.
You always can do that by your self:
elastic.indexOps(Person.class).putMapping(Person.class)
Related
I'm running into an issue with a Json schema validation.
I have a Java class like this
package com.ebc.jackson.exampe.data;
public class FormElement {
private String fieldName;
private String fieldType;
private Object value;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
I'm using below code to generate the schema:
JsonSchemaGenerator generator =
new JsonSchemaGenerator(objectMapper);
JsonNode schema = generator.generateJsonSchema(FormElement.class);
String strSchema = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
this code generates below schema
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "Form Element",
"type" : "object",
"additionalProperties" : false,
"properties" : {
"fieldName" : {
"type" : "string"
},
"fieldType" : {
"type" : "string"
},
"value" : {
"$ref" : "#/definitions/Object"
}
},
"definitions" : {
"Object" : {
"type" : "object",
"additionalProperties" : false,
"properties" : { }
}
}
}
In the request, I could receive a Json Object like
{
"fieldName": "user-name",
"fieldType": "textInput",
"value": "Alex"
}
When I try to validate this object against the Json schema, "value" attribute is not valid, it is expecting a "key: value" pair but, a string is found.
In the Java class the value attribute is Object because it could be a String, Integer, Boolean, etc.
My question is, how can I generate a schema to support different data types for "value" attribute?
You can use the anyOf property of schema :
Try the below one :
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Form Element",
"type": "object",
"additionalProperties": false,
"properties": {
"fieldName": {
"type": "string"
},
"fieldType": {
"type": "string"
},
"value": {
"$ref": "#/definitions/Object"
}
},
"definitions": {
"Object": {
"format": "",
"anyOf": [
{
"type": "object"
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "integer"
},
{
"type": "boolean",
"x-enumFlags": true
},
{
"type": "null"
}
],
"additionalProperties": false,
"properties": {}
}
}
}
Or you could try the pipe separator in type.In the schema you provided just change the value of type to "type": "string|object|integer|number". This notation didn't work for me in swagger but you can check if it works for you.
I have following JSON structure as input which can be nested and without nested. I want to fetch the JSON as input and process in Spring Boot application. How to create a class which dynamic key values in the JSON. It can be any key-value pairs in the JSON input. Below is the sample one.
Without Nested:
{
"mappings": {
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"salary": {
"type": "integer"
},
"date_of_birth": {
"type": "date"
}
}
}
}
With Nested:
{
"mappings": {
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"annual_salary": {
"type": "integer"
},
"date_of_birth": {
"type": "date"
},
"comments": {
"type": "nested",
"properties": {
"name": {
"type": "string"
},
"comment": {
"type": "string"
},
"age": {
"type": "short"
},
"stars": {
"type": "short"
},
"date": {
"type": "date"
}
}
}
}
}
}
I don't know how to create a class to support both with and without nested in single class. I have tried the following. It doesn't help.
public class Schema {
Mapping mappings;
public Mapping getMappings() {
return mappings;
}
public void setMappings(Mapping mappings) {
this.mappings = mappings;
}
public static class Mapping {
Property properties;
public Property getProperties() {
return properties;
}
public void setProperties(Property properties) {
this.properties = properties;
}
}
public static class Property {
Map<String, Map<String, Object>> field = new HashMap<>();
public Map<String, Map<String, Object>> getField() {
return field;
}
public void setField(Map<String, Map<String, Object>> field) {
this.field = field;
}
}
}
I have come across a scenario similar to this where it was possible that my JSON may not be having consistent Key-Value pairs.
I gave the following jackson annotation at class level so that whichever property not available in my model and which are present in the JSON will be ignored.
#JsonIgnoreProperties(ignoreUnknown = true)
I would like to create following json payload from the java classes. Only one condition is there, Subgroup1 can be null, meaning group may/may not have subgroup1. Not sure how can it be done. Any help would be highly appreciated. Thanks in advance! I can change the classes if needed.
{
"data" : [
{
"id": "1",
"name": "ab",
"children": [
{
"id": "1",
"name": "xyz",
"children": [
{ "id": "1",
"name": "opl"
} ]
}
]
},
{
"id":" 2",
"name": "cd",
"children": [
{
"id": "1",
"name": "ijk",
"children": [
{ "id": "1",
"name": "rty"},
{ "id": "2",
"name": "wsc"
} ]
},
{
"id": "2",
"name": "lmn",
"children": [
{ "id": "1",
"name": "qaz"},
{ "id": "2",
"name": "poi"
} ]
},
{
"id": "3",
"name": "opq",
"children": [
{ "id": "1",
"name": "edf"},
{ "id": "2",
"name": "bhgga"
} ]
}
]
},
{
"id": "3",
"name": "ef",
"children": [
{
"id": null,
"name": null,
"children": [
{ "id": "2",
"name": "ijyuht"
} ]
}
]
}
]
}
I have 3 different java classes to map objects.
Data.class
public class Data {
private Long id;
private String name;
private List<Subgroup1> children;
}
Subgroup1.class
public class Subgroup1 {
private Long id;
private String name;
private List<Subgroup2> children;
}
Subgroup2.class
public class Subgroup2 {
private Long id;
private String name;
}
Create Classes structure as below:
public class MainClass {
private List<Datum> data;
}
public class Datum {
private List<Child> children;
private String id;
private String name;
}
public class Child {
private List<Child> children;
private String id;
private String name;
}
below format you can use in Java, its just a way you can do it in multiples way, as i have expained in a easy way.
MainClass mainClass = new MainClass();
List<Child> level2List = new ArrayList<>();
Child level2Child = new Child();
level2Child.setName("opl");
level2Child.setId("1");
level2List.add(level2Child);
List<Child> childList = new ArrayList<>();
Child child = new Child();
child.setChildren(level2List);
child.setId("1");
child.setName("xyz");
childList.add(child);
Datum datum = new Datum();
datum.setChildren(childList);
datum.setId("1");
datum.setName("ab");
List<Datum> datumList = new ArrayList<>();
datumList.add(datum);
mainClass.setData(datumList);
System.out.println(new Gson().toJson(mainClass));
I have a JSONObject with some dynamic attributes that I want to convert into a class, I have tried a lot of examples on SO, but no solution.
My json string looks like this
{
"result": {
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
"assets": {
"r9F6wk8HkXrgYWoJ7fsv4VrUBVoqDVtzkH": [
{
"currency": "BTC",
"value": "5444166510000000e-26"
}
],
"rPFLkxQk6xUGdGYEykqe7PR25Gr7mLHDc8": [
{
"currency": "EUR",
"value": "4000000000000000e-27"
}
],
"rPU6VbckqCLW4kb51CWqZdxvYyQrQVsnSj": [
{
"currency": "BTC",
"value": "1029900000000000e-26"
}
],
"rpR95n1iFkTqpoy1e878f4Z1pVHVtWKMNQ": [
{
"currency": "BTC",
"value": "4000000000000000e-30"
}
],
"rwmUaXsWtXU4Z843xSYwgt1is97bgY8yj6": [
{
"currency": "BTC",
"value": "8700000000000000e-30"
}
]
},
"balances": {
"rKm4uWpg9tfwbVSeATv4KxDe6mpE9yPkgJ": [
{
"currency": "EUR",
"value": "29826.1965999999"
}
],
"ra7JkEzrgeKHdzKgo4EUUVBnxggY4z37kt": [
{
"currency": "USD",
"value": "13857.70416"
}
]
},
"ledger_hash": "980FECF48CA4BFDEC896692C31A50D484BDFE865EC101B00259C413AA3DBD672",
"ledger_index": 14483212,
"obligations": {
"BTC": "5908.324927635318",
"EUR": "992471.7419793958",
"GBP": "4991.38706013193",
"USD": "1997134.20229482"
},
"status": "success",
"validated": true
}
}
Is there something that I can use from the json.org or ObjectMapper?
The only part that is given me problem is the assets and the balances, I will appreciate all help in right direction
You should be able to deserialize this into classes like:
public class Response {
private Result result;
}
public class Result {
private String account;
private Map<String, List<Asset>> assets;
private Map<String, List<Asset>> balances;
private String ledger_hash;
private String ledger_index;
private Map<String, String> obligations;
private String status;
private boolean validated;
}
public class Asset {
private String currency;
private String value;
}
Trying to serialize a collection of non-primitive types using katharsis, but getting an empty collection all the time.
Response example:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Expected response:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{
tittle: "some title",
value: "some value"
}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Domain objects (getters, setters, constructor and other stuff omitted by using lombok #Data annotation):
#JsonApiResource(type = "products")
#Data
public class Product {
#JsonApiId
private Integer id;
private List<SimpleAttribute> simpleAttributes = new ArrayList<>();
private String variationGroup;
}
#Data
public class SimpleAttribute implements Serializable{
private String title;
private String value;
}
I do not want to use relationships in this case or to include attributes to "included" field. Is it possible in katharsis?
Not sure what actually was wrong, but the problem disappeared after I changed katharsis-spring version from 2.3.0 to 2.3.1.