Spring Data Elasticsearch

Spring Data Elasticsearch

Selamlar, projemizde Spring Boot ve Spring Data Elasticsearch kullanarak bir ürün objesini Elasticsearch’e kaydetme, güncelleme, silme ve getirme işlemlerini bir rest api yardımıyla yapacağız.

Projeyi aşağıdaki adresten inceleyebilirsiniz.

Elasticsearch yüksek düzeyde ölçeklenebilir açık kaynak bir full-text arama ve analiz motorudur. Büyük verileri hızlı ve neredeyse gerçek zamanlı olarak depolamanızı, aramanızı ve analiz etmenizi sağlar. Elasticsearch Netflix, Slack, Microsoft ve Uber gibi çeşitli firmalar tarafından kullanılmaktadır.

Elasticsearch’ün temel kavramları:

  • Near Real-Time(NRT): NRT bir döküman indexlendiğinde gerçek zamanlıya yakın bir sürede aranabilir bir duruma gelir.
  • Cluster: Verileri bir arada tutan ve bir ya da daha fazla node’u birbirine bağlayan ve arama yetenekleri sağlayan bir koleksiyondur.
  • Node: Cluster’ın bir parçası olan ve verileri depolayan, indexleme ve arama işlemine yardımcı olan sunucudur.
  • Index: Benzer özelliklere sahip belge koleksiyonu.
  • Document(Belge): Indexlenebilen temel data. Json formatındadır.
  • Shard ve Replica: Her index birden çok shard’a bölünebilir. Ayrıca bir index 0 replica yani kopyasız veya birden çok replicaya sahip olabilir. Bir dizinin replicası olduğunda primary shard ve replica shardlara(primary shardların kopyası) sahip olacaktır. Bu da örneğin primary shard’da donanımsal bir sıkıntı olduğunda replica shard işimize yarayacaktır.

Docker’da sırasıyla alttaki 2 komutu çalıştırarak bir Elasticsearch ayağa kaldırmış olacağız.

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.16.2

docker run -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.16.2

Docker’da ilgili container’ın running statüsünde olduğu gördükten sonra http://localhost:9200 adresinde aşağıdaki gibi bir json dosyası görüyor olmalıyız. Bu elasticsearch’ün ayakta olduğu anlamına gelir.

Daha sonra Spring Boot ile bir java projesi oluşturuyorum. Projemin pom.xml dosyası aşağıdaki gibi. spring-data-elasticsearch dependencysi ile Spring Boot ve Elasticsearch’ü birbirine bağlayabiliriz.

Application.java dosyamda SpringApplication.run methodu bulunmakta.Ayrıca @EnableElasticsearchRepositories(basePackages = “org.example”) annotation’ı ile ,Spring Data Elasticsearch’ün Spring Data repositorylerini taramasını sağlıyor. Bunun dışında @EnableSwagger2 annotation’ınını swagger için ekliyorum ve api methodunda da swagger’ın çalışmasını sağlayan kod bulunuyor.

ElasticClient.java dosyasında AbstractElasticsearchConfiguration classından extend alıyorum ve ClientConfiguration objesini kullanarak bir RestHighLevelClient objesi oluşturuyorum. Bu obje localhost:9200 adresine bağlantı kuruyor.

Product.java dosyasında @Document anatasyonu ile eğer indexName değerindeki index mevcut değilse index create işlemini sağlıyoruz. Burda objemizin içindeki fieldları @Field notasyonu ile giriyoruz type değerine field’ın type değerini name değerine de name değerini giriyoruz. id isimli field’a ise @Id notasyonunu kullanıyoruz.

Mapping Annotationları için daha fazla bilgiye docs.spring.io/spring-data/elasticsearch/do.. adresinden ulaşabilirsiniz.

ProductRepository interface’inde ise ElasticsearchRepository’den extend alıyor ve generic olarak değerlerini giriyoruz. Burda ElasticsearchRepository’nin sağladığı methodlara ek olarak kendi yazdığımız findProductByName methodu var. Bu method @Query annotation’ı içindeki değer sayesinde aşağıdaki query’yi Elasticsearch’e gönderir ve List sonucu bekler.

{  
  "query": {  
    "match": {  
      "name": {  
        "query": "name"  
      }  
    }  
  }  
}

Query örneklerine docs.spring.io/spring-data/elasticsearch/do.. adresinden ulaşabilirsiniz.

ProductService.java classında üstte bahsettiğimiz ProductRepository classını autowired ile çekerek tüm productları dönen allProducts,Product kayıt etmemizi sağlayan saveProduct, id ile productGet etmemizi sağlayan getproductById, girilen isim değerine göre liste olarak product dönen findProductByName ilgili ürünü update etmemizi sağlayan updateProductById ve ürün silmemizi sağlayan deleteProductById methodları var. Burada productRepositorynin bize sağladığı methodları kullanıyoruz sadece updateProductById’de aşağıdaki kod bloğu var.

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()  
.withQuery(*matchQuery*("id", id).minimumShouldMatch("100%"))  
.build();

SearchHits<Product> products =elasticsearchOperations.search(searchQuery, Product.class, IndexCoordinates.*of*("productindex"));

Product product=  products.getSearchHit(0).getContent();

Bu kod bloğuna göre öncelikle dışardan gelen değerin id değeriyle match olduğunu kontrol eden bir NativeSearchQuery ‘imiz var . Daha sonrasında bu query’yi gönderip SearchHits tipinde bir değişken alıyoruz ve burdaki products.getSearchHit(0).getContent() bizim update etmek istediğimiz product objesini bize dönüyor.

ProductController classında ise ProductService’de yazmış olduğumuz methodların rest endpointine dönüştüğü yer diyebiliriz. Örneğin @GetMapping(“/products/{id}”) için productService.getProductById methodunu çağırıyoruz.

Şimdi apiyi ve elastic’i kaldırıp swagger üzerinden endpointlerimizi test edelim.

http://localhost:8080/swagger-ui.html adresine giriyorum ve POST /api/products endpointine aşağıdaki json dosyasını execute ediyorum.

{
"id": "17",
"name": "test ürünü 17",
"price": 17
}

Benim örneğimde http://localhost:9200/productindex/_doc/17 (localhost:9200/(indexAdı)/_doc/idDeğeri)adresine gidip baktığımızda aşağıdaki kaydın eklendiğini görüyoruz.

Daha sonra sırasıyla allProducts, getProductById ve findProductByName methodlarımı çağırıp create ettiğim product’ın geldiğini görüyorum.

Oluşturduğum product’ı update ediyorum ardından get endpointleriyle get ederek update olduğunu görüyorum.

Oluşturduğum product’ı delete ediyorum ardından get endpointleriyle get ederek product’ın silindiğini görüyorum.

Bu yazımda size spring boot elasticsearch hakkında bilgi vermeye çalıştım. Bir sonraki yazımda bu apiye nasıl test yazabiliriz onunla alakalı bir yazı yazmayı planlıyorum görüşmek üzere.

Kaynak:

https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients

https://www.baeldung.com/spring-data-elasticsearch-tutorial

https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html

https://medium.com/inside-freenow/centralized-logs-with-elastic-stack-and-apache-kafka-7db576044fe7

https://www.elastic.co/guide/en/elasticsearch/reference/current/scalability.html

http://www.ilkaygunel.com/spring-data-elasticsearch-demo/