I am usign spring-data-elasticsearch 2.1.4.RELEASE , How can I update a field mapping for a type using ElasticsearchOperations?
when I try operations.putMapping(EsJob.class); again ,there is exception:
because the field createdBy already exist, but I want to update it .
Anyone have a better solution for this?
Servlet.service() for servlet [dispatcher] in context with path [/api] threw exception [Request processing failed; nested exception is java.lang.IllegalgumentException: Mapper for [createdBy] conflicts with existing mapping in other types:
[mapper [createdBy] has different [store] values, mapper [createdBy] has different [analyzer]]] with root cause
java.lang.IllegalArgumentException: Mapper for [createdBy] conflicts with existing mapping in other types:
[mapper [createdBy] has different [store] values, mapper [createdBy] has different [analyzer]]
at org.elasticsearch.index.mapper.FieldTypeLookup.checkCompatibility(FieldTypeLookup.java:153)
at org.elasticsearch.index.mapper.FieldTypeLookup.copyAndAddAll(FieldTypeLookup.java:115)
at org.elasticsearch.index.mapper.MapperService.merge(MapperService.java:381)
at org.elasticsearch.index.mapper.MapperService.merge(MapperService.java:320)
at org.elasticsearch.cluster.metadata.MetaDataMappingService$PutMappingExecutor.applyRequest(MetaDataMappingService.java:306)
at org.elasticsearch.cluster.metadata.MetaDataMappingService$PutMappingExecutor.execute(MetaDataMappingService.java:230)
at org.elasticsearch.cluster.service.InternalClusterService.runTasksForExecutor(InternalClusterService.java:468)
at org.elasticsearch.cluster.service.InternalClusterService$UpdateTask.run(InternalClusterService.java:772)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:231)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:194)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
You can't update mappings on existing indices in general. That's why this is also not provided by the ElasticsearchOperations-Interface.
You can apply a new mapping for a new index or add new fields into an existing mapping - or you can delete mappings by deleting the index as well. According to this, you receive an error when putting another mapping in terms to update the existing one.
If major changes are required, you'll have to reindex your data with this new mapping. See this post for doing this without downtime.
Related
In a CrudPanel I have the need to update some items (not through the CRUD dialog). Something like this:
#Transactional
...
instance.setSomeAttribute(newValue);
return savedInstance = instanceRepository.save(instance);
Calling refreshAll on the dataProvider after the update produces the warning Got an RPC for non-existent node: xxxx. Also I guess it is a little expensive to refresh all items if just one changed.
Calling the specific refresh item, on the other side, refreshItem(instance), gives Object of class [...MenuItem] with identifier [xxxx]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
I also tried to pass newInstance to refreshItem, same result.
Can somebody indicate how to proceed?
Check equals and hashCode that they don't contain fields that may have changed when you call refreshItem.
I have following Quartz job in my Grails application:
class DataWarehouseJob {
def execute(context) {
LeadList list = context.mergedJobDataMap.get('list')
if (list.processing) {
return
}
list.processing = true
list.save(failOnError: true)
...
}
}
list is passed as a parameter on job triggerNow call and it's populated with correct values. This list already exists in database. However, when it tries to save the list, following error occurs:
org.quartz.JobExecutionException: org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [haystack.LeadList#169]; nested exception is org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [haystack.LeadList#169]
at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:111)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [haystack.LeadList#169]; nested exception is org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [haystack.LeadList#169]
...
Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [haystack.LeadList#169]
at org.hibernate.engine.internal.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:618)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:301)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:244)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:109)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90
...
I have tried adding flush: true as parameter to save function, calling merge on list before save, annotating class with #ExecuteInJTATransaction, saving LeadList withNewSession, but nothing helped - same error always occurs on same line (list.save)
The weirdest thing is that this code worked before and I'm not sure which change could break it - there were no commits of changes touching this class in quite some time.
The code is written in Grails 3.1.5 and running on Tomcat 8.
I don't wanna delete the question, since solution might benefit someone.
The problem was because job was accepting the LeadList object and I guess it created the copy of it instead of passing the object by reference, and that's what caused the problem.
Solution is to send ID of the object as a parameter to job instead of the whole object, and in job to first fetch object by ID before making changes in database:
// LeadList list = context.mergedJobDataMap.get('list')
long listId = context.mergedJobDataMap.get('listId')
LeadList list = LeadList.findById(listId)
Still, I have no idea how passing the whole object worked before and then at some point started causing the issue all of a sudden.
I'm upgrading a 2.3 app to 2.4.4 and I have several domains that use List fields similar to the following and I'm receiving an error as described here.
class Game {
List score
static hasMany = [ score: Integer ]
}
I'm assuming use of the above is the actual cause of the problem but I can't be sure because the error message doesn't point to a domain.
Is this type of list definition not good grails practice?
I get the error:
2014-10-31 16:26:32 ERROR [context.GrailsContextLoaderListener] Error initializing the pplication: Error creating bean with name 'transactionManagerPostProcessor':
....
Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.hibernate.MappingException: Association references unmapped class: java.util.List
UPDATE
I found the domain and the problem associated with the error. Here's the problem domain and associated List. If I remove the List, the problem is corrected.
class Team {
List teamTourney
static hasMany = [ teamTourney: TeamTourney ]
}
For anyone that might receive this error in the future you can add
log4j = {
debug 'org.codehaus.groovy.grails.orm.hibernate.cfg'
}
to the config and it will tell you what class and property is causing the problem.
Is this type of list definition not good grails practice?
The code that you show there should be fine. See the project at https://github.com/jeffbrown/integerlist.
The problem was a List referencing an undefined field. Among the domains in my project was a type-o in the field name associated with a List. It would be nice if the error message pointed at the location of the error, a point also in this post.
Thanks, Scott.
I have configured Swagger for REST web services, it works well and fetches my Request, Response parameters with clean documentation but it fails to display the Model Schema when using #ModelAttribute annotation
Is it something that I have to do to make Swagger accept such annotation as it is with #RequestBody?
I ran into a similar problem in using #ModelAttribute on a method parameter and it turned out that the object was not a proper POJO and could not be serialized. My first step to figuring this out was to enable trace level logging of the Swagger/Spring classes with the following XML block added to my log4j2.xml:
<Logger name="com.mangofactory" level="trace"></Logger>
This caused the following logged events to be output:
13:15:43.954 [localhost-startStop-1] DEBUG com.mangofactory.swagger.readers.operation.parameter.ModelAttributeParameterExpander - Expanding parameter type: class org.joda.time.DateTime
13:15:43.955 [localhost-startStop-1] DEBUG com.mangofactory.swagger.readers.operation.parameter.ModelAttributeParameterExpander - Attempting to expanding field: private static final long org.joda.time.DateTime.serialVersionUID
13:15:43.956 [localhost-startStop-1] DEBUG com.mangofactory.swagger.readers.operation.parameter.ModelAttributeParameterExpander - Skipping expansion of field: private static final long org.joda.time.DateTime.serialVersionUID, not a valid bean property
Depending on your object and its needs, you may need to define a mapping using the SwaggerSpringMvcPlugin.directModelSubstitute or make sure your object has matching getters/setters. Another option is to use the Jackson Data Binding library.
So, my team has been having multiple issues while upgrading our existing app from Grails 1.3.7 to 2.1.0. The latest headache occurs when trying to save a domain class object that has a composite key based on two other domain objects.
We are hanging Grails on a legacy database which we cannot readily change, so all of the domain classes have custom mappings to hook up with it. Below is a quick, slimmed down version of the domain classes in question.
Class Product {
Short prodKey
String name
static hasMany = [groupProduct: GroupProduct]
//Also includes mapping to legacy db and simple constraints
}
Class Group {
Short groupKey
String name
static hasMany =[ groupProduct: GroupProduct]
//This domain class has several other mappings and variables, but they are not relevant
}
Class GroupProduct {
Group group
Product product
Character indicator
static belongsTo = [Product,Group]
static mapping = {
id composite: ["group", "product"]
group lazy:false, column:"GROUP_KEY", joinTable:"GROUP"
product lazy:false, column:"PROD_KEY", joinTable:"PRODUCT"
version false
}
//Only constraint is indicator is Y or N
}
In the app a user is able to select multiple products for a group to turn on or off via a checkbox list. The parameters contain the groupKey and a list of all checked products. The controller gets an instance of the specified group and then a list of all Products. The products are matched against the list in the parameters, every time a match is found a GroupProduct object is made with the indicator set to 'Y', otherwise a GroupProduct object is made with the indicator set to 'N'.
Class GroupProductController{
//allowedMethods and other actions...
def update = {
def groupInstance = Group.get(params.GroupId)
def groupProducts= []
def products= Products.list()
products.each{
def indicator = ...//code to get value of check box for this Product. Returns either Y or N, works as expected
def groupProduct= new GroupProduct(group:groupInstance ,
product:it,
indicator: indicator)
groupProducts.add(groupProduct)
}
groupInstance.discard()
groupProducts.each{
it.save(failOnError: true, flush:true)//This line throws a DB2 SQL error. SQLCODE=-407
}
}
}
Resulting error is:
org.hibernate.util.JDBCExceptionReporter|DB2 SQL Error: SQLCODE=-407, SQLSTATE=23502, SQLERRMC= , DRIVER=3.50.152
org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener|Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not update: [GroupProduct#component[group,product]{product=Product#1, group=Group#938926168}]
at com.controllers.ProductGroupController$_closure2_closure8.doCall(ProductGroupController.groovy:86)
at com.nationwide.nas.beam.controllers.ProductGroupController$_closure2.doCall(ProductGroupController.groovy:79)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Caused by: com.ibm.db2.jcc.b.lm: DB2 SQL Error: SQLCODE=-407, SQLSTATE=23502, SQLERRMC= , DRIVER=3.50.152
at com.ibm.db2.jcc.b.wc.a(wc.java:575)
at com.ibm.db2.jcc.b.wc.a(wc.java:57)
at com.ibm.db2.jcc.b.wc.a(wc.java:126)
at com.ibm.db2.jcc.b.tk.b(tk.java:1593)
at com.ibm.db2.jcc.b.tk.c(tk.java:1576)
at com.ibm.db2.jcc.t4.db.k(db.java:353)
at com.ibm.db2.jcc.t4.db.a(db.java:59)
at com.ibm.db2.jcc.t4.t.a(t.java:50)
at com.ibm.db2.jcc.t4.tb.b(tb.java:200)
at com.ibm.db2.jcc.b.uk.Gb(uk.java:2355)
at com.ibm.db2.jcc.b.uk.e(uk.java:3129)
at com.ibm.db2.jcc.b.uk.zb(uk.java:568)
at com.ibm.db2.jcc.b.uk.executeUpdate(uk.java:551)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
... 5 more
The error occurs when trying to save the GroupProduct objects. According to IBM the error code -407 is caused by AN UPDATE, INSERT, OR SET VALUE IS NULL, BUT THE OBJECT COLUMN column-name CANNOT CONTAIN NULL VALUES. However, none of the variables for the GroupProducts are actually null. The Group and Product instances are pulled straight from the database, which means they have already been validated and shouldn't have any constraint violations, and I can see that the indicator field is being set correctly.
There is also no problem when running this code under the original 1.3.7 version of the project. If anyone could shed some light on this I'd be very grateful. Thanks
After much debugging and hunting through code, I managed to find the issue. All of our domain classes extend an abstract base domain, which has a createdTimestamp and updatedTimestamp field. Before doing an insert we set both fields, and before doing an update we update the updatedTimestamp.
The issue was that when we were saving, the new object had a null createdTimestamp field, which was throwing the error. Added in code to check if the GroupProduct object we were making already existed, and if so set the new objects createdTimestamp field to the existing object's before saving. Now everything works as expected.
Its strange that Grails 1.3.7 did not have any issues with this code, though. Only thing I can figure is that it automatically associated the new objects with existing ones in the DB. Probably the strangest behavior change I've found during the upgrade process. Hope this helps anyone running into a similar issue.