Oracle Full Text Search
Oracle, VERITABANI | Fatih Özdemir | October 8, 2009 at 3:17 pm
Full Text Search Nedir?:
Bilişim dünyasında veritabanı kullanmış veya veritabanıyla işlem yapmış herkes index kelimesini duymuştur. Index in veritabanındaki kullanımını hemen bir örnekle açıklayalım. Mesela epeyce kalın kaufmann’ın eski pascal türü bir kitap aldınız ve kitabın içinde bir şeylere bakacaksınız, 1000 sayfalık kitabın her sayfasını tek tek çevirmek epeyce uzun ve zahmetli bir iş. Bunun için kitabın hemen başındaki indexine bakarız ve hızlıca göz gezdirip aradığımız konunun hangi sayfada olduğunu bulup direkt o sayfayı açarız.Aynen bu örnekte olduğu gibide databaselerde verileri kendilerine özel algoritmalarla indexler ve o veriye gitmek gitmek istendiğinde bu indexleri kullanarak o satırı bulur.Full Text Index ise indexlenmek istenen alan eğer text içeriyorsa ki bu bir html dosyası pdf de olabilir, bu tip verileri indexlemek için kullanılır.
Mesela bir gazetecesiniz ve 10 yıllık tüm gazetelerde çıkmış “ekonomik kriz” kelimelerini bulmak istiyorsunuz. Karşınızdaki datanın büyüklüğünü bir gözünüzün önüne getirin. Burada hemen aklınıza şu soru gelebilir google bunu peki nasıl yapıyor? Google Search’ün arkasında kullanılan index algoritmasının kesinlikle çok büyük önemi var fakat bu algoritmanın kullandığı arkada yüz binlerce server olduğunu unutmamak gerekir. Halbuki siz şirketinizde yada web sayfanızda arama yaparken 1-2 bilgisayar ile yetinmek zorundasınız. Onun için şimdilik google ile boy ölçüşmeye kalkışmamak gerekJ
Bu devasa text datalarını işe yarar şekilde indexlenmesine full text index denir. Burarada işe yarar şekilde kelimesi önemli bunu dokümanın ilerleyen kısımlarında anlatacağım. Her database’in kendine has bir full text algoritması ve kullanım biçimi var. Ben bu dokümanda Oracle Full Text nedir ne değildir biraz bahsetmeye çalışacağım ve bunu soru cevap şeklinde yapacağım. Dokümanın bundan sonra kısımlarında Full Text Index FTI olarak kısaltılacaktır.
FTI çeşitleri
Oracle da 3 çeşit index çeşidi vardır bunlar
CONTEXT Indexes
CTXCAT Indexes
CTXRULE Indexes
Bu indexlerin ne manaya geldiğine bakalım.
Context Indexes : Bu index çok yüksek miktarda text içeren datalar için kullanılır. Örneğin pdf,word,html gibi datalar için.
CtxCat Indexes : Bu index contexte göre daha az olan text alanlar i.in kullanılır. Örneğin varchar2 tipinde bir field için bu index kullanılabilir. CtxCat index için synchronize işlemi gerekmez bu otomatik olarak yapılır.
CtxRule Indexex : Daha çok document based indexlerde kullanılır. Detaylı bilgi için aşağıdaki adresi ziyaret edebilirsiniz.
www.oracle- base.com/articles/9i/FullTextIndexingUsingOracleText9i.php#CONTEXTIndexes
FTI de kullanılan terimler ve açıklamaları
Keyword: Arama yapmak için kullandığımız kelime veya kelimeler için kullanıyoruz
Phrase Search : Aramaya yaparken belli kelimelerin bütününü aramak için kullanılır. “Fatih Özdemir” kelimelerini beraber aramak gibi. Genellikle aranacak kelimelerin başına sonuna “ koyarak aradığınızda arama motorları phrase search yapar. Oracle’da bunu destekliyor.Proximity Search : Aranılan kelimeler arasında yakınlığa bakarak yapılan aramadır. Bir çok arama motoru bu özelliği desteklemektedir(Yahoo,Google).
Örneğin :
“uncle * bob” OR “bob * uncle” aramasını yazdığınızda uncle ile bob ve uncle ile bob arasında en fazla 2 kelime olacak şekilde arama sonucu döner.
Wildcard Search : Arama yaparken bir harfin yerine geçecek bir karakter kullanılarak yapılan aramalardır.
Örneğin Kara* Bu aramanın sonucunda Karadeniz,Karabük,Karaman vb sonuçlar dönecektir
Wildcard search aramayı yavaşlatıcı bir tekniktir.
FTI İşlemleri
Create Index
En basit şekilde bir tablodaki bir alana fti yukarıdaki sql ile atılır. Burada field_name alanı ile verilen field text bir field olmak zorunda yani bu sql doğal olarak numeric bir field için çalışmaz zaten hata verecektir.
Bu sql execute olduğunda tablodaki satır sayınıza ve alan içinde text in büyüklüğüne göre epeyce sürebilir. Onun için böyle bir sqli çalıştırmadan önce iki kere düşünün zira database’i lock edebilirsiniz ve bu tabloyu kullanan tüm yazılımlarınız durabilir.
Querying
Normalde fti atılmamış bir text alanda sorgulama yapmak şöyle bir sql kullanırız:
Fti atıldıktan sonraki sorgumuz artık şöyle olacaktır:
Score
Score operatörü etxt içinde geçen kelimelerin sıklıklarına göre size bir değer döndürür. Örneğin haebrler tablosundaki title alanında “java” kelimesini arıyorsunuz.
title “java is best language” olan ve “i like java. java is best language” olan 2 satır var
bu sorguda score operatörü kullanırsanız satırlardan birinde daha fazla java geçtiği için onun score’u daha yüksek dönecektir.
Bu sorguda contains’in içinde kullandığımız 1 rakamı label için verilmiş bir değerdir. Score kullanırken de burada yazdığımız değeri kullanıyoruz. Başka bir örnek yapalım. Bu örnekte double contains nasıl kullanılır onu göstermeye çalıştım.
OR CONTAINS(body,’ORACLE’,2)>0
Bir fti indexin parametrelerini değiştirmek yada rebuild etmek için kullanılan ALTER INDEX REBUILD syntax’ını dokümanın ilerleyen bölümlerinde inceleyeceğiz.
Aşağıdaki sql ile atılan indexi kaldırabilirsiniz. Kaldırma işlemi atılan index ne kadar büyük olursa olsun çok uzun sürmez saniyeler içerisinde index drop edilir.
Fti için kullanılan tüm elementleri ve parametreleri bu dokümanda anlatamayacağım çünkü epeyce uzun bir doküman olur. Ben çok sık kullanılan genel elementlerden bahsedeceğim.
Bir databasede birden fazla alanda arama yapmak istiyorsak bu elementi kullanıyoruz. Hemen örnekle açıklayalım
News adında bir tablo var ve bu tablonun title,headline,writer,body adından alanları olsun. Aramayı tüm bu alanların hepsinde birden yapmak istiyorum. Bunun nasıl olacağına bakalım
Önce my_multi_datastore adında bir preference oluşturuyorum.
Daha sonra bu oluşturduğum multi_colum_datastore preference olan my_datastore’a beraber kullanmak istediği alanlari attribute olarak ekliyorum.
Sonra bu alanların hepsini sorgulamak için kullanacağımız dummy bir field oluşturuyoruz. Index atarken bu dummy alanı kullanacağız. Aslında bu field sanal sadece bizim diğer fieldları tek bir field üzerinden sorgulayabilmemiz için gerekli. Bu dummy alan değiştiğinde index syncronize triggeri yazılmışsa çalışır.
full_text adında dummy bir field oluşturuyorum.
Bu tablonun indexini atmak için aşağıdaki sql’i çalıştırıyoruz.
Sql çalıştığında IX_NEWS_TEXT adında NEWS tablosunun FULL_TEXT alanı için bir index oluşturulur. Parametre olarak yukarıda tanımladığım my_datastore verdiğim için full_text alanın birden fazla field ile bağlantılı olduğunu da söylemiş oluyorum.
Yukarıdaki sql ‘title,headline,writer,body’ alanlarında “oracle” kelimesini arayacak ve sonuçlarını getirecek.
Oracle artık index’inde tuttuğu düzce kelimesi için yukarıdaki satırı silecektir ve Erdoğan Akyazı kelimeleri için ise yukarıdaki kaydı ekleyecektir. Siz bir kaydı güncellediğinizde oracle index synronization işlemini otomatik olarak yapmaz. Bunu nasıl yapacağımıza bakalım.
Oracle 10G ile gelen bir özellik ile bir veri database e kayıt edildiğinde otomatik syncronize olacak şekilde bir parametre kullanarak bunu gerçekşeltirebiliriz. Yada bu işlemi belli periodlar halinde yapılması için oracle_jobs için ayarlayabiliriz. Başka bir yöntemde synchronize işlemini tablonun after insert event’ına trigger olarak yazarız.
Bu üç yönteme de sırayla bakalım.
Yukarıda parametre verilerek nasıl çoklu fieldlarda arama yapılabildiğini yazmıştım. Aynı index üzerinden devam edersek aşağıdaki sql yazıldığında haber tablosuna bir kayıt eklendiğindei silindiğinde veya güncellediğinde kısacası her hangi bir commit event’ı olduğunda fti synchronize olacaktır
Triggera yazma
Aşağıdaki şekilde bir trigger oluşturuyoruz.
TRIGGER my_trigger
before insert or update or delete on news
BEGIN
ctxsys.ctx_ddl.sync_index(‘IX_NEWS_TEXT’);
END my_trigger;
News tablosuna herhangi bir kayıt eklendiğinde silindiğinde veya tablodan bir kayıt silindiğinde trigger çalışıp indexi synchronize edecektir.
Oracle Jobs’a ekle
Oracle enterprise manager üzerinden jobs kısmına indexin ne kadar zamanda bir synchronize olmasını istiyorsak ayarlıyoruz. Bu yöntem performans olarak en iyi yöntemdir. Toplu olarak belli periodlarda verileri synchronize eder ve indexleri günceller.
Lexer bir dile özgü işlemler yapmak için kullanılır. Bu konuda epeyce detaylı bir konu ben Türkçe için en çok ihtiyaç duyacağımız özelliklerinden bahsetmeye çalışacağım.
Lexer çeşitlerinden Basic_Lexer çok işimize yarayacak bir element. Basic_Lexer’ın çok bazı attributelerini aşağıda yazdım.
| continuation | Satır sonunda bir kelimeyi ayırmak için kullanılan karakter. Bizdeki tire(-) işareti |
| printjoins | Bir kelimenin içinde geçecek geçerli karakterler. Mesela gel-git gelmesini gel-git olarak indexlemek istiyorsam burada belirtmem gerekiyor. |
| punctuations | Kelime sonlarındaki noktala işaretleridir. Default olarak nokta(.) soru işareti(?) ve ünlem(!) set edilmiştir. Örneğin tavşan. Kelimesiiçin nokta(.) işareti indexlenmez sadece tavşan kelimesi indexlenir. Bu attribute sadece son karaktere bakar yani printjoins de nokta işareti kullanılsa bile punctutations da var ise nokta işareti göz önüne alınmadan indexlenecektir. |
| skipjoins | Bir kelimenin içinde geçtiğinde bu karakterleri pas geçerek kelimeyi indexler. Örneğin gel-git kelimesin gelgit olarak indexlemek istiyorsak tire(-) işaretini buraya ekleriz. printjoins and skipjoins için aynı karakterler kullanılamaz. |
| newline | Satır sonu karakterini belirlemek için kullanılır. Default olarak newline(\n) karakteri kullanılır. Seçim yapabileceğiniz direkt karakter ise carriage_return(\r) dür. |
| base_letter | Bu attribute default olarak NO yani disabled olarak gelir. Fakat Türkçe için çok gerekli bir özellik. Mesela arama yaparken eğer u-ü o-ö gibi noktalı noktasız harfleri beraber olarak aramak istiyorsak bu özelliği YES(enabled) yapmamız gerekiyor. Örneğimizde bunu attribute kullanacağız. |
| mixed_case | Default olarak NO(disabled) olarak gelir ve tüm token(kelime)lar büyük harfe çevrilir. |
| index_stems | Index atılırken hangi kelime kökleri için hangi dilin seçileceği seçilir. |
Türkçe aramalarda daha çok istenen özellik noktalı veya noktasız arama da yapılsa sonuçların dönmesi. Örneğin “fotoğraf “ kelimesinin bulunmasını istiyorsam fotograf da yazılsa fotoğraf da yazılsa aynı sonuçların dönmesi. Aynı şey tabi diğer harfler içinde geçerli yani büyük için buyuk yazılarak aranması gibi.
Bunu yapabilmek için yukarıda bahsettiğim gibi lexer kullanacağız. Önce bir lexer create ediyoruz sonra buna attribute veriyoruz ve indeximiz create ederken bu daha önce oluşturduğumuz lexerı parametre olarak veriyoruz. Tıpkı multi_column_datastore gibi.
Aşağı bununlar ilgili sqlleri yazdım.
ctx_ddl.set_attribute(‘my_lexer’,'BASE_LETTER’,'YES’);
Bu preference’i prefix_index substring_index gibi indexleme özelliklerini kullanmak için uyguluyoruz. Doğal olarak bu özellikler nedir diye soracaksınız hemen anlatmaya çalışacağım.
Basic Wordlist bazı attribute lerini yazacağım. Yukarıda da olduğu gibi bunlar benim daha önce Türkçe için kullandığım özellikler.
| substring_index | Default olarak No(disabled) olarak geliyor. Bir kelime indexlenirken substringlere ayrılarak indexleniyor. Index süresini 4 kata kdar arttırıyor. Fakat soldan ve iki taraflı wildcard sorgularında çok daha iyi performans sağlıyor. Örneğin %mail% %konsolos |
| prefix_index | Defalult olarak No(Disabled) olarak geliyor. Sağdan yapılan wildcard sorguları için daha fazla performans sağlıyor. Tabi doğal olarak daha fazla yer ve daha uzun index süresi demek. |
| prefix_length_min | Default değeri 1 dir. Prefix_indexin minimum kac karakterden itibaren yapılacağını belirtir. |
| prefix_length_max | Default değeri 64 dür. Maximum kac karaktere kadar prefix_index atılacağını belirtir. |
| wlidcard_maxterms | Default değeri 5000 dir ve 1-15000 arasında değer alır. Wildcard bir arama sonucunda dönene kelime sayısının maximum miktarını belirtir. Eğer bu sayıdan fazla sonuç dönerse oracle exception atar.Örnek vermek gerekirse eğer siz ev% şeklinde bir arama yaparsanız ve ev% ile başlayan 5000 den fazla index değeri dönerse hata alırsınız.
|
Şimdi gerçek örnekler ile anlatmaya çalışayım. mywordlist adında bir basic_wordlist oluşturacağım.
ctx_ddl.set_attribute(‘mywordlist’,'PREFIX_INDEX’,'TRUE’);
ctx_ddl.set_attribute(‘mywordlist’,'PREFIX_MIN_LENGTH’,3);
ctx_ddl.set_attribute(‘mywordlist’,'PREFIX_MAX_LENGTH’,4);
Yukarıdaki özelliklere göre prefix_index yapılacak ve minimum 3 ve maximimum 4 karakter uzunluğundaki keliemeler prefix_index e tabi tutulacak. Bunun nedemek olduğunu açıklamak isterim.
Tabloda her bir satırda aşşağıdaki gibi olsun Ev Süt Araba Bebek Mama Oracle yukarıdaki özelliklere göre bu textleri indexlediğinde Ev Süt Araba Bebek Mam MamaŞeklinde indexleyecektir. 3ten küçük olanlar için ekstra bir indexleme yapmıyor. Boyutu 4 ten büyük olanlar içinde prefix indexleme yapmıyor(Bebek,Araba) fakat Mama kelimesi için hem mam hemde mama kelimelerin ayrı ayrı indexledi.
Indexleme yaparken bazı kelimelerin indexlenmesini istemeyebiliriz. Örneğin googleda arama yaparken “the,as,in,at” gibi kelimeleri kullandığınızda google bu kelimeleri ignore ederek aradım gibi bir mesaj veriyor. Bu tip kelimelerin indexlenmemesi için stoplist preference kullanıyoruz. Nasıl kullanacağımıza bakalım.
Sql’ile stopwords isminde bir basic_stoplist oluşturuyoruz. Oluşturduğumuz bu stopliste kelimeler eklemek için
ctx_ddl.add_stopword(’stopwords’, ‘bu’);
ctx_ddl.add_stopword(’stopwords’, ‘için’);
ctx_ddl.add_stopword(’stopwords’, ‘göre’);
stoplist’den kelime çıkarmak için ise aşağıdaki şekilde sql’imizi yazıyoruz.
Yukarıda anlattığım tüm parametreleri kullanarak News tablomuza index atmak istersek aşağıdaki gibi bir sql yazmamız gerekli.
Tags: full text search, index, Oracle


Tweet This
Digg This
Save to delicious
Stumble it










Oracle Full Text Search çok faydalı oldu. Teşekürler, emeğinize sağlık reklamalarada tıkliyim mi ? şaka şaka
Full Text olayında Microsoft mu daha başarılı yoksa Oracle’mı?