Dotnet 5.0’de Postgresql Full Text Search ile Arama Motoru yapmak.
Bu yazımda, postgresql full text search’ü dotnet 5’de nasıl kullanılabileceğini bir api yazarak test edeceğiz.
Geliştirme Yaptığım Ortam
- Windows 10
- Postgresql 12
- Dotnet 5.0
- EntityFramework Core 5
Postgresql Full Text Search hakkında detaylı bilgi için şu makalemi inceleyebilirsiniz.
Bir api projesi yapacağız bu api postgresql fts ile aradaki köprü olacak. Postgresqli .net platformunda kullanabilmek için npsql kütüphanesinden faydalanacağız.
Dotnet 5.0 web api seçenekleriyle projemi açıyorum
MovieController adında bir api controller açalım
appsetting.json ve startup‘da veritabanı bağlantı ayarlarını tanımlayalım
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConnectionStrings": { "PostgresqlConnection": "User ID=postgres;Password=123;Server=localhost;Port=5432;Database=FirstMyDb;Integrated Security=true;Pooling=true;" } } |
Startup.cs:
1 2 3 4 5 6 7 8 9 10 11 |
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddDbContext<ApplicationDbContext>( options => options.UseNpgsql(Configuration.GetConnectionString("PostgresqlConnection"))); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "MovieSearchApp", Version = "v1" }); }); } |
Basit bir api yapacağımız için monolit(tek katmanlı) bir mimariyle yapacağız. Models adında klasör içinde entitylerimiz ve Dbcontext sınıfımızı oluşturacağız
Daha önce veritabanında oluşturduğumuz tabloya göre hareket edeceğiz ilgili makale şu linkte. Movie entitysinde arama yapacağımız bir SearchKeywords columnu var ve burada önümüze iki seçenek çıkıyor
- Npsql librarysinden faydanalarak tsvector sütununu direkt olarak NpgsqlTsVector tipinde ayarlayabiliriz. Böylece npsql’in Full text search için özel oluşturduğu extensionlardan faydalanabiliriz
- Diğer Seçenek ise tsvector columnumuzu direkt string olarak tanımlamak bu durumda ise extensionlarla değil saf sql yazarak faydalanabiliriz
İki yöntemi de nasıl yazacağımızdan ve artı eksi yönlerinden bahsedeceğim ilk yöntemle başlayalım.
Movie.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[Keyless] public class Movie { public int Rank { get; set; } public string Title { get; set; } public string Genre { get; set; } public string Description { get; set; } public string Director { get; set; } public string Actors { get; set; } public int? Year { get; set; } public decimal? Rating { get; set; } public string Votes { get; set; } public NpgsqlTsVector SearchKeywords { get; set; } } |
MovieController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Route("api/[controller]/[action]")] [ApiController] public class MovieController : ControllerBase { private ApplicationDbContext _db; public MovieController(ApplicationDbContext Db) { _db = Db; } [HttpGet] public IActionResult Find(string q) { var model = _db.Movies.Where(p => p.SearchKeywords.Matches(q)).ToList(); return Ok(model); } } |
Swagger üzerinde apimizi test edelim
Şimdi 2.yöntemimizi test edelim. Önce SearchKeywords propertyimizi string olarak değiştirelim. Değiştirdikten sonra Find actionuna ham sql sorgumuzu yazalım
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[HttpGet] public IActionResult Find(string q) { if (!String.IsNullOrEmpty(q)) { var model = _db.Movies .FromSqlRaw(@"Select * from public.""Movies"" where ""SearchKeywords"" @@ to_tsquery('english',{0})", q) .Select(m => new { Title = m.Title, Description = m.Description, Rank = m.Rank }).ToList(); return Ok(model); } return Ok(""); } |
Test ettiğimizde aşağıdaki sonuçlar gelecek
Sonuç
Her iki yöntemde de sonuçları elde ettik ama Ham sql zorunlu olmadıkça yazılmamalı eğer ki orm framework’ü bazı sql desteklerini vermiyorsa mecbur kullanılabilir örnek olarak npsql entity framework kütüphanesinde tsvector desteği yok mecburen ham sql yazılmak zorunda. Diğer türlü sql sorgularıyla yapılacak işlemler ile hızlı sonuç alabilirsiniz ama temiz kod yazılamaz ileride problemlere sebep olur.
Elasticsearch’e ihtiyaç olmayan durumlarda yani az datamızın olması bunun yanında, syntax’ının çabuk öğrenilmemesi gibi nedenlerle postgresql bu konuda gayet güzel bir alternatif olmakta.