Spring Boot සහ Elasticsearch: Full-Text Search පහසුවෙන්! – SC Guide

Mastering Full-Text Search with Spring Boot and Elasticsearch SC Guide
ආයුබෝවන් කට්ටියටම! අද අපි කතා කරන්න යන්නේ දැන් කාලේ software development වලදී අත්යවශ්ය දෙයක් වෙලා තියෙන Full-Text Search ගැන. ඔයාලා කවදාවත් හිතලා තියෙනවද Amazon, eBay වගේ sites වල අපි search කරනකොට, අපේ query එකට ගැලපෙන results කොහොමද එච්චර ඉක්මනට එන්නේ කියලා? සාමාන්ය databases (SQL වගේ) වලින් මේ වගේ complex search operations කරන්න ගියාම ටිකක් අමාරුයි, performance issues එන්නත් පුළුවන්. අන්න ඒකට තමයි අපිට Elasticsearch වගේ powerful tools ඕන වෙන්නේ.
අද මේ article එකෙන් අපි බලමු Spring Boot application එකක් එක්ක Elasticsearch integrate කරලා, powerful full-text search functionalities අපේ system එකට add කරගන්නේ කොහොමද කියලා. ඔයාලා Spring Boot ගැන දන්නවා නම්, මේක ඔයාලට අලුත් දෙයක් නෙවෙයි. හැබැයි Elasticsearch ගැන එච්චර දන්නේ නැත්නම්, මේක ඔයාලට හොඳ ආරම්භයක් වේවි!
Elasticsearch කියන්නේ මොකක්ද? (What is Elasticsearch?)
සරලවම කිව්වොත්, Elasticsearch කියන්නේ open-source, distributed, RESTful search සහ analytics engine එකක්. ඒක Apache Lucene මත තමයි හදලා තියෙන්නේ. සාමාන්ය databases වගේ මේක data store කරන්නත් පුළුවන්, හැබැයි මේකේ ප්රධානම feature එක තමයි real-time search සහ analytics capabilities. හිතන්නකෝ ඔයාලගේ website එකේ blog posts මිලියන ගණනක් තියෙනවා කියලා. ඒ posts අතරින් specific words, phrases හෝ tags search කරනකොට ඒක ඉතාම වේගයෙන් කරන්න Elasticsearch වලට පුළුවන්.
Elasticsearch වල ප්රධාන වාසි කිහිපයක් මෙන්න:
- Full-Text Search: ඕනෑම text field එකක search කරන්න පුළුවන්. Spelling mistakes, synonyms, relevance ranking වගේ දේවල් manage කරන්න පුළුවන්.
- Distributed Nature: Data shards වලට කඩලා nodes කිහිපයක් අතර distribute කරන නිසා, extreme scalability සහ fault tolerance ලැබෙනවා.
- JSON Documents: Data store වෙන්නේ JSON documents විදියට. ඒක නිසා schema-less, flexible data modelling කරන්න පුළුවන්.
- RESTful APIs: Simple RESTful API එකක් හරහා communicate කරන්න පුළුවන්.
- Real-time Analytics: Log analysis, business analytics වගේ දේවලටත් ඉතාම වේගයෙන් results ලබාගන්න පුළුවන්.
සාමාන්ය relational databases වලට වඩා Elasticsearch වෙනස් වෙන්නේ, ඒක data store කරන්නේ inverted index කියන ක්රමය භාවිතා කරලා වීම නිසා. මේකෙන් search operations ඉතාම වේගවත් වෙනවා. හිතන්න පොතක පිටු අංක එක්ක වචන තියෙන තැන Index එකක් තියෙනවා වගේ. ඒක නිසා query එකක් ආවම, සම්පූර්ණ data එක scan කරන්නේ නැතුව, කෙලින්ම index එකෙන් අදාල තැනට යන්න පුළුවන්.
Spring Boot සහ Elasticsearch එකට වැඩ කරන්නේ කොහොමද? (How do Spring Boot and Elasticsearch work together?)
Spring Boot කියන්නේ Java developersලාට applications හදන්න තියෙන ඉතාම ජනප්රිය framework එකක්. Spring Data project එකෙන් data access technologies ගොඩකට support කරනවා, ඒ අතර Elasticsearch වලටත් support එකක් තියෙනවා – ඒක තමයි Spring Data Elasticsearch.
Spring Data Elasticsearch මගින් අපිට Elasticsearch එක්ක වැඩ කරන්න පුළුවන් පහසු ක්රම කිහිපයක් සපයනවා:
- Repository abstraction: JPA repositories වගේම Elasticsearch repositories හදන්න පුළුවන්. මේකෙන් boilerplate code අඩු වෙනවා.
- Automatic index mapping: Java objects (entities) Elasticsearch documents වලට map කරන්න පුළුවන්.
- Templating: Low-level Elasticsearch operations කරන්න පුළුවන්
ElasticsearchRestTemplate
හෝElasticsearchOperations
වගේ tools.
Spring Boot application එකක් Elasticsearch එක්ක connect කරන්න නම්, මුලින්ම අපිට Elasticsearch instance එකක් ඕන වෙනවා. Local development වලදී Docker හරහා Elasticsearch run කරන එක තමයි පහසුම ක්රමය. Docker Desktop install කරලා නැත්නම්, දැන්ම install කරගන්න.
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elastic/elasticsearch:7.17.0
මේ command එකෙන් Elasticsearch 7.17.0 version එක Docker container එකක් විදියට run වෙනවා. discovery.type=single-node
කියන්නේ development purpose වලට single-node cluster එකක් හැටියට run කරන්න කියන එක. Production වලට නම් cluster setup එකක් ඕන වෙනවා.
Project Setup සහ Configurations (Project Setup and Configurations)
හරි, දැන් අපි Spring Boot project එකක් හදාගෙන Elasticsearch integrate කරන්නේ කොහොමද කියලා බලමු. ඔයාලට Spring Initializr (start.spring.io) එකෙන් අලුත් project එකක් හදාගන්න පුළුවන්. Dependencies විදියට මේවා add කරගන්න:
- Spring Web
- Spring Data Elasticsearch
- Lombok (කෝඩ් ලියන එක පහසු කරගන්න)
Project එක download කරලා IDE එකක open කරගත්තට පස්සේ, pom.xml
file එකේ dependencies
section එක මෙහෙම වෙන්න ඕන (ඔයාලා තෝරගත්ත dependencies අනුව වෙනස් වෙන්න පුළුවන්):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.properties Configuration
ඊළඟට, src/main/resources/application.properties
file එකට Elasticsearch connection details add කරන්න ඕන. අපි Docker වලින් run කරපු Elasticsearch instance එක 9200 port එකේ තමයි run වෙන්නේ. Spring Boot එකේ නවතම versions වලදී high-level REST client එක automatic configure කරනවා.
# Elasticsearch Configuration
spring.data.elasticsearch.client.rest.uris=http://localhost:9200
spring.data.elasticsearch.repositories.enabled=true
මේ settings ටිකෙන් කියන්නේ Spring Boot application එක http://localhost:9200
කියන address එකේ තියෙන Elasticsearch instance එකට connect වෙන්න ඕන කියලා.
Elasticsearch Entity (Document) එකක් හදමු
Elasticsearch වල data store වෙන්නේ documents විදියට. Spring Data Elasticsearch වලදී අපි Java class එකක් document එකක් විදියට define කරනවා. අපි Product
කියන document එකක් හදමු.
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Document(indexName = "products")
public class Product {
@Id
private String id;
private String name;
@Field(type = FieldType.Text, analyzer = "english") // Text field for full-text search
private String description;
private double price;
private String category;
}
@Document(indexName = "products")
: මේ annotation එකෙන් කියන්නේ මේProduct
class එක Elasticsearch වලproducts
කියන index එකට map වෙනවා කියලා. Index එක කියන්නේ relational database එකක table එකක් වගේ දෙයක්.@Id
: මේක document එකේ unique identifier එක.@Field
: මේකෙන් document එකේ fields configure කරන්න පුළුවන්. අපිdescription
field එකFieldType.Text
විදියට set කරලාanalyzer = "english"
කියලත් දීලා තියෙනවා. Analyzer එකකින් text එක index කරනකොට කොහොමද analyze කරන්නේ කියලා කියනවා (e.g., lowercase කරනවද, stop words අයින් කරනවද වගේ).
Data Indexing සහ Search Operations (Data Indexing and Search Operations)
දැන් අපි බලමු මේ Product
documents Elasticsearch වලට save කරලා, search කරන්නේ කොහොමද කියලා.
Elasticsearch Repository එකක් හදමු
Spring Data JPA වගේම, Spring Data Elasticsearch වලටත් repositories හදන්න පුළුවන්. මේකෙන් CRUD operations සහ custom search queries පහසුවෙන් execute කරන්න පුළුවන්.
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
List<Product> findByName(String name);
List<Product> findByDescriptionContaining(String keyword);
List<Product> findByCategory(String category);
// Custom query for more advanced search
List<Product> findByNameContainingOrDescriptionContaining(String nameKeyword, String descriptionKeyword);
}
මෙතන ElasticsearchRepository<Product, String>
කියන්නේ Product
document එකට සහ String
type එකේ ID එකකට අදාල repository එකක්. Spring Data magic එකෙන් findByName
, findByDescriptionContaining
වගේ methods වලට අදාල queries automatic generate කරනවා.
Service Layer එකක් හදමු
අපි මේ repository එක භාවිතා කරලා data save කරන්න සහ search කරන්න ProductService
එකක් හදමු.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public Product saveProduct(Product product) {
return productRepository.save(product);
}
public Optional<Product> getProductById(String id) {
return productRepository.findById(id);
}
public List<Product> getAllProducts() {
return (List<Product>) productRepository.findAll();
}
public List<Product> searchProductsByName(String name) {
return productRepository.findByName(name);
}
public List<Product> searchProductsByDescription(String keyword) {
return productRepository.findByDescriptionContaining(keyword);
}
public List<Product> searchProducts(String query) {
return productRepository.findByNameContainingOrDescriptionContaining(query, query);
}
public void deleteProduct(String id) {
productRepository.deleteById(id);
}
}
REST Controller එකක් හදමු
දැන් අපි මේ service එක expose කරන්න REST Controller එකක් හදමු. මේකෙන් අපිට API calls හරහා products add කරන්න, search කරන්න පුළුවන්.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@PostMapping
public ResponseEntity<Product> createProduct(@RequestBody Product product) {
Product savedProduct = productService.saveProduct(product);
return new ResponseEntity<Product>(savedProduct, HttpStatus.CREATED);
}
@GetMapping("/{id}")
public ResponseEntity<Product> getProductById(@PathVariable String id) {
return productService.getProductById(id)
.map(product -> new ResponseEntity<>(product, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@GetMapping
public ResponseEntity<List<Product>> getAllProducts() {
List<Product> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}
@GetMapping("/search")
public ResponseEntity<List<Product>> searchProducts(@RequestParam String query) {
List<Product> products = productService.searchProducts(query);
return new ResponseEntity<>(products, HttpStatus.OK);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable String id) {
productService.deleteProduct(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
ප්රායෝගිකව කරලා බලමු (Let's try it out practically!)
දැන් ඔයාලා Spring Boot application එක run කරන්න. (main
method එක තියෙන class එක run කරන්න). අපි Postman, curl, හෝ Insomnia වගේ tool එකක් භාවිතා කරලා API calls ගහලා බලමු.
1. Products Index කරන්න (Index Products):
POST http://localhost:8080/api/products
{
"name": "Samsung Galaxy S23",
"description": "Latest Android smartphone from Samsung with amazing camera and battery life. High performance phone.",
"price": 1200.00,
"category": "Electronics"
}
{
"name": "Apple MacBook Pro 14",
"description": "Powerful laptop for professionals. Features M2 Pro chip and stunning Liquid Retina XDR display. Best for coding and video editing.",
"price": 2500.00,
"category": "Electronics"
}
{
"name": "Logitech MX Master 3S Mouse",
"description": "Advanced wireless mouse for ultimate comfort and productivity. Smooth scrolling and customizable buttons.",
"price": 100.00,
"category": "Accessories"
}
මේ වගේ products කිහිපයක් add කරන්න.
2. Products Search කරන්න (Search Products):
GET http://localhost:8080/api/products/search?query=phone
Results වලට Samsung Galaxy S23
එක එන්න ඕන. මොකද ඒකේ description එකේ phone
කියන වචනය තියෙන නිසා.
GET http://localhost:8080/api/products/search?query=laptop
Results වලට Apple MacBook Pro 14
එක එන්න ඕන.
GET http://localhost:8080/api/products/search?query=wireless mouse
Results වලට Logitech MX Master 3S Mouse
එක එන්න ඕන.
දැන් ඔයාලට පේනවා ඇති, සාමාන්ය database search එකකට වඩා මේක කොච්චර powerful ද කියලා. wireless mouse
වගේ phrase එකකට වුණත් අදාල product එක හරියටම හොයලා දෙනවා.
ඔබටම කරන්න පුළුවන් ව්යායාමයක්! (An exercise for you to try!)
ඔයාලා Product
entity එකට අලුතින් tags
කියන List<String> field එකක් add කරන්න. ඊට පස්සේ ProductRepository
එකට findByTagsContaining(String tag)
වගේ method එකක් add කරලා, tag එකක් දීලා search කරන විදියට Controller එකත් update කරලා බලන්න. මේකෙන් ඔයාලට තවත් හොඳ අවබෝධයක් ලැබෙයි.
Practical Tips සහ Best Practices (Practical Tips and Best Practices)
Elasticsearch කියන්නේ ලොකු topic එකක්. අපි මෙතනින් basic එකක් කතා කළේ. Advanced use cases වලදී මේ දේවල් වැදගත් වෙනවා:
- Custom Analyzers:
english
analyzer එකට අමතරව, ඔයාලට සිංහල වගේ භාෂාවලට හෝ specific use cases වලට custom analyzers හදන්න පුළුවන්. - Mapping Types:
@Field
annotation එකෙන් fields වල data type, analyzer, index settings වගේ දේවල් manage කරන්න පුළුවන්. Dynamic mapping වෙනස් කරන්න ඕන නම්, mapping templates භාවිතා කරන්න පුළුවන්. - Aggregations: Elasticsearch වල aggregations කියන්නේ powerful feature එකක්. Search results වලට අමතරව data summary (e.g., product categories අනුව count එක, price range අනුව products) ලබාගන්න මේක භාවිතා කරන්න පුළුවන්.
- Pagination සහ Sorting: ලොකු result sets handle කරනකොට pagination (
Pageable
object එක) සහ sorting (Sort
object එක) අත්යවශ්යයි. - Performance Tuning: Data volumes වැඩි වෙනකොට queries optimize කරන්න, cluster performance tuning කරන්න, caching strategies භාවිතා කරන්න සිද්ධ වෙනවා.
- Security: Production environment එකකදී Elasticsearch cluster එකට security layer එකක් add කරන එක අනිවාර්යයි (e.g., X-Pack security).
අවසාන වශයෙන් (In Conclusion)
Spring Boot සහ Elasticsearch කියන්නේ modern applications වලට full-text search සහ analytics capabilities add කරන්න තියෙන ඉතාම powerful combination එකක්. මේ article එකෙන් අපි basic setup එක සහ operations ටිකක් කතා කළා. මේක ඔයාලට මේ subject එක ගැන තවදුරටත් ඉගෙන ගන්න හොඳ පදනමක් වෙන්න ඇති.
දැන් ඉතින් වැඩේ තියෙන්නේ ඔයාලා අතේ! මේ concepts ටික ඔයාලගේ project එකකට add කරලා practical experience එකක් ගන්න බලන්න. ප්රශ්න තියෙනවා නම්, ඔබේ අත්දැකීම් comment section එකේ කියන්න! අපි ඒ ගැන කතා කරමු.
මීළඟ ලිපියකින් හමුවෙමු! Happy Coding!