2016-11-22 5 views
3

Ich habe ein Dokument mit vielen Feldern (einige geschachtelt) indiziert auf elasticsearch. Zum Beispiel:Teilupdate mit Spring Data Elasticsearch Repository

{ 
    "id" : 1, 
    "username" : "...", 
    "name" : "...", 
    "surname" : "...", 
    "address" : "...", 
    "age": 42, 
    ... 
    "bookmarks" : [{...}, {...}], 
    "tags" : [{...}, {...}] 
} 

nur einige eingereicht wird in meiner Einheit zugeordnet (ich will nicht das gesamte Dokument zur Karte):

@Document(indexName = "...", type = "...") 
public class User { 
    @Id 
    private int id; 
    private String username; 
    private String address; 

    // getter/setter methods 

} 

In der Serviceklasse würde Ich mag ein Teil-Update tun mit ElasticsearchRepository, ohne alle Felder in der Einheit des Dokuments abbildet:

public class UserServiceClass { 

    @Autowired 
    private UserElasticsearchRepository userElasticsearchRepository; 

    public void updateAddress(int id, String updatedAddress) { 
    User user = userElasticsearchRepository.findOne(id); 
    user.setAddress(updatedAddress); 
    userElasticsearchRepository.save(user); 
    } 
} 

aber speichern Methode überschreibt das gesamte Dokument:

{ 
    "id" : 1, 
    "username" : "...", 
    "address" : "..." 
} 

Teil udpdate von ElasticsearchRepository nicht unterstützt zu sein scheint. So habe ich ElasticsearchTemplate, um eine teilweise Aktualisierung zu machen, zum Beispiel:

public class UserServiceClass { 

    @Autowired 
    private UserElasticsearchRepository userElasticsearchRepository; 

    @Autowired 
    private ElasticsearchTemplate elasticsearchTemplate; 

    public void updateAddress(int id, String updatedAddress) { 
    User user = userElasticsearchRepository.findOne(id); 
    if (user.getUsername().equals("system")) { 
     return; 
    } 

    IndexRequest indexRequest = new IndexRequest(); 
    indexRequest.source("address", updatedAddress); 
    UpdateQuery updateQuery = new UpdateQueryBuilder().withId(user.getId()).withClass(User.class).withIndexRequest(indexRequest).build(); 
    elasticsearchTemplate.update(updateQuery); 
    } 
} 

aber scheint ein wenig überflüssig haben zwei ähnliche Referenzen (Repository und ElasticsearchTemplate).

Kann mir jemand eine bessere Lösung vorschlagen?

Antwort

4

Statt beide mit ElasticsearchTemplate und UserElasticsearchRepository injiziert in Ihr UserServiceClass, können Sie Ihre eigenen benutzerdefinierte Repository und lassen Sie Ihre vorhandenen UserElasticsearchRepository es erweitern implementieren.

Ich nehme an, dass Ihr vorhandenes UserElasticsearchRepository so etwas aussieht.

public interface UserElasticsearchRepository extends ElasticsearchRepository<User, String> { 
    .... 
} 

Sie müssen neue Schnittstelle erstellen Name UserElasticsearchRepositoryCustom. In dieser Schnittstelle können Sie Ihre benutzerdefinierte Abfrage-Methode auflisten.

public interface UserElasticsearchRepositoryCustom { 

    public void updateAddress(User user, String updatedAddress); 

} 

Dann implementieren Ihre UserElasticsearchRepositoryCustom durch eine Klasse UserElasticsearchRepositoryImpl und implementieren Sie Ihre eigene Methode innen mit injizierten ElasticsearchTemplate

public class UserElasticsearchRepositoryImpl implements UserElasticsearchRepositoryCustom { 

    @Autowired 
    private ElasticsearchTemplate elasticsearchTemplate; 

    @Override 
    public void updateAddress(User user, String updatedAddress){ 
     IndexRequest indexRequest = new IndexRequest(); 
     indexRequest.source("address", updatedAddress); 
     UpdateQuery updateQuery = new UpdateQueryBuilder().withId(user.getId()).withClass(User.class).withIndexRequest(indexRequest).build(); 
     elasticsearchTemplate.update(updateQuery); 
    } 
} 

Danach wird nur verlängert Ihre UserElasticsearchRepository mit genannt erstellen UserElasticsearchRepositoryCustom sollte es so aussehen.

public interface UserElasticsearchRepository extends ElasticsearchRepository<User, String>, MessageRepositoryCustom { 
    .... 
} 

Schließlich sollten Sie Service-Code wie folgt aussehen.

public class UserServiceClass { 

    @Autowired 
    private UserElasticsearchRepository userElasticsearchRepository; 

    public void updateAddress(int id, String updatedAddress) { 
    User user = userElasticsearchRepository.findOne(id); 
    if (user.getUsername().equals("system")) { 
     return; 
    } 
    userElasticsearchRepository.updateAddress(user,updatedAddress); 
    } 
} 

Sie können auch als auch Ihre Benutzerfindung Logik in die benutzerdefinierten Repository Logik bewegen, so dass Sie nur Benutzer-ID und die Adresse in der Methode übergeben können. Ich hoffe, das ist hilfreich.

1

Sie können ElasticSearchTemplate auch verwenden, um Ihr Benutzerobjekt anstelle der Repository-Schnittstelle abzurufen. Sie können NativeSearchQueryBuilder und andere Klassen zum Erstellen Ihrer Abfrage verwenden. Damit können Sie zwei ähnliche Referenzen aus Ihrer Klasse vermeiden. Lassen Sie mich wissen, ob dies Ihr Problem löst.

+0

Dank Shahnaz, in meiner endgültigen Lösung habe ich nur ElasticSearchTemplate verwendet, um Benutzerobjekt zu lesen und zu aktualisieren. Aber ich hoffe, dass es möglich sein wird, auch teilweise mit Spring Data Elasticsearch Repositories zu aktualisieren. – pz74

+0

AFAIK im Moment gibt es kein Teilupdate mit Repositories, wenn Sie etwas finden, lassen Sie es mich bitte auch wissen. Vielen Dank –

Verwandte Themen