Skip to content

Don't try to write readonly id property after indexing #2230

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sothawo opened this issue Jul 19, 2022 · 3 comments · Fixed by #2249
Closed

Don't try to write readonly id property after indexing #2230

sothawo opened this issue Jul 19, 2022 · 3 comments · Fixed by #2249
Assignees
Labels
type: bug A general bug

Comments

@sothawo
Copy link
Collaborator

sothawo commented Jul 19, 2022

In AbstractElasticsearchTemplate.updateIndexedObject() the following code is used to set the id property of an entity:

if (indexedObjectInformation.getId() != null && idProperty != null
		&& idProperty.getType().isAssignableFrom(String.class)) {
	propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
}

Here it must be checked as well if the id property is writeable - check reactive part as well

@sothawo sothawo added the type: bug A general bug label Jul 19, 2022
@sothawo sothawo self-assigned this Aug 1, 2022
sothawo added a commit to sothawo/spring-data-elasticsearch that referenced this issue Aug 4, 2022
sothawo added a commit that referenced this issue Aug 4, 2022
sothawo added a commit that referenced this issue Aug 4, 2022
Original Pull Request #2249
Closes #2230

(cherry picked from commit acf02a1)

# Conflicts:
#	src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java
@sothawo sothawo added this to the 5.0 M6 (2022.0.0) milestone Sep 2, 2022
@puppylpg
Copy link
Contributor

puppylpg commented Nov 17, 2022

after not writing readonly id back into java object, how could we solve this situation now?

To make it clearer, here is the situation we are facing:

  1. in elaticsearch mapping, there is a id field;
  2. but its value is different from _id;

in spring-data-elasticsearch 4.4.1, i handled this situation by using @ReadOnlyProperty as the answer posted above:

public class Entity {

    @Id
    @ReadOnlyProperty
    private String realId;

    @Field(value = "id", type = FieldType.Keyword)
    private String fieldId;

    @Field(type = FieldType.Long)
    private long whatever;

  // other fields...
}

the mapping is:

{
  "entity":{
    "mappings":{
      "properties":{
        "id":{
          "type":"keyword"
        },
        "whatever":{
          "type":"long"
        }
....
....
      }
    }
  }
}

If the doc in elasticsearch is {_id: a, _source: {id:b, whatever:xxx}}, the Entity object's properties are all set well after deserializing, like fieldId=a, realId=b, whatever=xxx CORRECTION realId=a, fieldId=b, whatever=xxx.

However, after upgrading to 4.4.3 with changes in this issue, realId=null now.

If i delete the @ReadOnlyProperty on realId field, it'll generate an additional realId in the elasticsearch mapping, which is totally not allowed.

So how could we get the same effect like 4.4.1 now? How could we still get _id value without writing another new field like realId into the mapping?

Thanks in advanced.

@sothawo
Copy link
Collaborator Author

sothawo commented Nov 17, 2022

If the doc in elasticsearch is {_id: a, _source: {id:b, whatever:xxx}}, the Entity object's properties are all set well after deserializing, like fieldId=a, realId=b, whatever=xxx.

I think there is an error in your example: After reading fieldId should be b and realId should be a.

The workaround with adding the @ReadOnlyProperty only worked because of the wrong implementation in Spring Data Elasticsearch which wrote a value back into a property although this is marked as being read only. By fixing this behaviour in this issue this does not work any longer. I need to update my answer in SO.

The real problem is, that the id property is not only used as identifier in Elasticsearch but also is written into the source - not into the mapping. The addition to the mapping you see is done by Elasticsearch when the data is written to the source and there is no mapping for the field.

What would be needed here is a possibility to configure Spring Data Elasticsearch to not write the id property into the document (I created #2364).

To get the _id back into your realId in the current version, leave the @ReadOnlyProperty on the id property. In addition to that, you need a AfterConvertCallback:

#import org.springframework.data.elasticsearch.core.event.AfterConvertCallback;

@Component
public class EntityAfterConvertCallback implements AfterConvertCallback<Entity> {

	@Override
	public Entity onAfterConvert(Entity entity, Document document, IndexCoordinates indexCoordinates) {
		entity.setRealId(document.getId());
		return entity;
	}
}

This is invoked after the Entity is set up - and is missing the realId; in this callback you then set the document's id (as returned from Elasticsearch) into the realId property.

@puppylpg
Copy link
Contributor

puppylpg commented Nov 18, 2022

Thanks for the quick response. I'll try this workaround, and totally agree what expresses in #2364
As for the example above, yeah i wrote it wrongly, the realId should be a. I'll correct it to avoid misunderstand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants