» Witam! » Blog

Blog

Tak na próbę…

Z pewnością wiadomości będą dotyczyły zagadnień, którymi zajmuję się zawodowo, czyli języków programowania (w szczególności Rubiego), przetwarzania języka naturalnego i sztucznej inteligencji.

| Opublikowano 17:44 14-07-2009. Ostatnia modyfikacja 17:44 14-07-2009 [apohllo] | Komentarze (2)

poliqarpr 0.0.5

Poliqarpr jest nakładką dla Rubiego, pozwalającą w prosty sposób korzystać z serwera Poliqarp.

Poliqarp – serwer korpusów

Sam Poliqarp został pomyślany jako narzędzie ułatwiające pracę z korpusami tekstów. Jego zasadnicze przeznaczenie to wyszukiwanie fragmentów tekstów na potrzeby różnych zadań z dziedziny przetwarzania języka naturalnego. W obecnej chwili jest wykorzystywany w projekcie Narodowego Korpusu Języka Polskiego, ale został zaprojektowany w sposób, który pozwala stosować go również dla innych języków.

Co więcej – język zapytań Poliqarpa pozwala wyszukiwać słowa w korpusie nie tylko w oparciu o odmienione formy (wtedy nie różniłby się on specjalnie od funkcjonalności baz danych z wyszukiwaniem pełnotekstowym), ale pozwala np. określić, formę podstawową (tzw. lemat) słowa, a znalezione zostaną wszystkie wystąpienia, również form derywowanych (np. możemy zadać pytanie o “bój”, a w wynikach otrzymamy formy odmienione: boju, boje, bojom).

Również ta funkcjonalność nie jest związana wyłącznie z językiem polskim (choć ma zastosowanie głównie dla języków fleksyjnych), ani nie jest przywiązana do jednego zbioru tagów. Dzięki temu, w zależności od zastosowanego narzędzia, możemy korzystać z alternatywnych zbiorów tagów, nawet w ramach jednego języka.

Poliqarpr – klient napisany w Rubim, dla serwera Poliqarp

Poliqarpr, jak było wspomniane, jest napisanym w Ruby klientem, dla serwera Poliqarp. Jest on dostępny w publicznym repozytorium na GitHubie. Możemy go stamtąd pobrać za pomocą poniższego polecenia:

$ git clone git://github.com/apohllo/poliqarpr.git

Oczywiście jest on również dostępny jako gem na gemcutterze:

 # sprawdzamy wersję rubygems
$ gem -v
1.3.5 #=> OK!
 # dodajemy gemcutter do listy repozytoriów, jeśli wcześniej na niej nie był
$ gem sources -a http://gemcutter.org 
 # instalujemy poliqapr
$ gem install poliqarpr -a http://gemcutter.org
Successfully installed poliqarpr-0.0.5
1 gem installed
Installing ri documentation for poliqarpr-0.0.5...
Installing RDoc documentation for poliqarpr-0.0.5...

Jeśli wszystko przebiegnie bez zakłóceń możemy zacząć testować poliqarpa. Ponieważ jednak bez korpusu nie ma to większego sensu, dostępny jest również gem poliqarpr-corpus, który zawiera przykładowy korpus dla języka polskiego (zrównoważony słownik frekwencyjny).

Instalacja jest równie prosta:

$ gem install poliqarpr-corpus

W tym momencie musimy uzbroić się w odrobinę cierpliwości, bo korpus ma rozmiar kilku megabajtów.

Poliqarpr nie jest jedynym klientem dla serwera Poliqarp – dostępna jest również wersja w Javie, napisana przez autorów serwera. W stosunku do klienta javowego otrzymujemy jednak kilka udogodnień:
  • specyfikacja w formie testów
  • segmenty, fragmenty oraz rezultaty zapytań są pełnoprawnymi klasami
  • jest napisany w Rubim ;)

W szczególności to, że rezultaty zapytań są klasami, pozwala w łatwy sposób tworzyć paginację. Po szczegóły najlepiej zajrzeć do dostępnych w repozytorium speców.

Przykład użycia

Przypuśćmy, że mamy na naszym komputerze korpus języka polskiego o wielkości 250 mln segmentów, pobrany ze strony korpus.pl. Załóżmy, że znajduje się w katalogu /home/user/korpus. Co należy zrobić, aby można było go wygodnie przeglądać lub wykorzystać w programie napisanym w Rubim?

Po pierwsze musimy upewnić się, że serwer poliqarp jest zainstalowany i działa. Najprościej wykonać w linii poleceń następującą komendę:

$ poliqarpd &

Jeśli nie pojawią się żadne błędy, oznaczać to będzie, że serwer poliqarp został uruchomiony.

Następnie możemy skorzystać z serwera w programie napisanym w Rubim. Na wstępie musimy załadować zainstalowany wcześniej gem, stworzyć klienta oraz załadować korpus:

require 'poliqarpr'
client = Poliqarp::Client.new("TEST")
client.open_corpus("/home/user/korpus/all")
client.right_context = 10
client.left_context = 10
client.lemmata = :all
client.buffer_size = 1000

Kiedy tworzymy klienta, możemy przekazać opcjonalny parametr będący nazwą sesji z serwerem (pozwala odróżniać od siebie wiele jednocześnie połączonych klientów). Potem możemy otworzyć korpus (polecenie open_corpus), podając ścieżkę do jego katalogu, wraz z nazwą (tutaj używamy korpusu 250 mln segmentów, którego nazwa to “all”).

Opcjonalnie możemy również ustawić różne parametry dot. zwracanych rezultatów:
  • rozmiar prawo- i lewostronnego kontekst
  • szczegóły opisu segmentów
  • rozmiar bufora wyników, itp.

Kiedy dokonamy tych wstępnych ustaleń, możemy pobrać wyniki, dla wybranego zapytania (szczegóły składni języka zapytań omówione są w artykule na stronie dr. hab. Adama Przepiórkowskiego):

result = client.find("[base=kot]")
result[0..5].each do |excerpt|
  putes excerpt
end
 # – kukułka – piła – kot Zaznacz te obrazki, które
 # burza osy – ptaki – kot ptak – zegar – samochód
 # – orkiestra – telefon – kot Posłuchaj uważnie nagranych dźwięków i
 # ptaszek – burza lew – kot lecąca z kranu woda –
 # strumyk telefon – sowa – kot baran – lew – ptaszek

W powyższym przykładzie szukamy w korpusie wszystkich fragmentów, w których występuje wyraz “kot” w dowolnej formie. Następnie wyświetlany 6 pierwszych rezultatów. Każdy z rezultatów jest jednak pełnoprawnym obiektem, więc możemy przyjrzeć mu się szczegółowo:

result[0].author
#=> Małgorzata Pamuła
result[0].title
#=> Wczesne nauczanie języków obcych...
result[0].short_context.join("")
#=>  – kukułka – piła – kot Zaznacz te obrazki, które

API w chwili obecnej jest nieźle rozbudowane i udokumentowane, więc nie będę omawiał go szczegółowo.

Na koniec nie możemy zapomnieć o zamknięciu połączenia z serwerem:

client.close
gem | nlp | poliqarpr | ruby | Opublikowano 13:08 10-12-2009. Ostatnia modyfikacja 14:06 10-12-2009 [apohllo] | Komentarze (0)

cyc-console 0.0.5

Ponieważ opisane w poprzednim poście testy nowego serwisu do składowania gemów wypadły pomyślnie, postanowiłem umieścić tam nową wersję mojego gemu cyc-console.

Udało mi się zaimplementować następujące funkcjonalności:
  • autouzupełnianie poleceń Cyc (póki co na podstawie pliku użytkownika ~/.cyc_functions)
  • autouzupełnianie symboli Cyc (na podstawie odpowiedzi zwróconych przez serwer)
Niestety nadal pozostaje trochę problemów do rozwiązania:
  • obcinanie zbyt długich odpowiedzi (to samo jednak dzieje się w zwykłej konsoli Cyca)
  • problemy z poleceniami wielowierszowymi (problem bierze się z kolorowanego znaku zachęty – readline niepoprawnie oblicza długość linii i jakoś dziwnie się zawija, póki co nie znalazłem rozwiązania, które działałoby w Rubim)
  • błędy nie są manifestowane inaczej niż przez nil
  • to co wysyłane jest na STDOUT nie jest widoczne

Dzięki skorzystaniu z gemcuttera mogłem spokojnie dodać zależność od colors, bez dodatkowych problemów w trakcie testowania. Zatem instalacja (o ile mamy gemcuttera w repozytoriach) nie powinna teraz stanowić większego problemu. Dzięki rezygnacji z githuba, gem nazywa się teraz po prostu cyc-console, zatem polecenie instalacyjne wygląda teraz następująco:

$ sudo gem install cyc-console

Jeśli nie mamy zainstalowanego gema colors, zostanie od doinstalowany automagicznie.

cyc | gem | ruby | Opublikowano 11:19 08-10-2009. Ostatnia modyfikacja 12:42 08-10-2009 [apohllo] | Komentarze (0)

gemcutter

Kiedy opublikowałem ostatniego newsa i chciałem upewnić się, czy faktycznie cyc-console jest dostępne jako gem, ku mojemu zdziwieniu okazało się, że nie – charakterystyczna rubinowa ikona w Github, nie była aktywna. Zatem szybko przeszedłem do panelu konfiguracji projektu i już chciałem włączyć obsługę gemów (a w głowie dyndała mi myśl – czy rzeczywiście nie zrobiłem tego wcześniej), moje zdziwienie było jeszcze większe – w opcjach nie znalazłem możliwości budowania gemów!

Github hostował co najmniej kilka spośród gemów, które wyprodukowałem (są to zazwyczaj nieduże projekciki, które wykorzystuję w projektach z dziedziny NLP), choć w gruncie rzeczy niedawno doszedłem do wniosku, że schemat nazewnictwa, który wykorzystują (nazwa_uzytkownika-nazwa_gemu) jest dosyć niewygodny. W szczególności, jeśli chcemy w trakcie testów instalować gem lokalnie, a później go upublicznić przez gituhub, to oba gemy mają odmienną nazwę. Kiedy mamy jakieś zależności pomiędzy takimi gemami, to sprawa jeszcze bardziej się komplikuje, bo przy testowaniu gemów zależnych, trzeba by albo zmieniać nazwę zależności (aby wybierany był gem lokalny), albo wrzucać na github gem o nowym numerze, co jest tym bardziej niewygodne, bo trwa długo, a co gorsza, jest niezgodne z praktyką inżynierii oprogramowania, gdyż nieprzetestowany moduł nie powinien być publikowany.

Ostatnio rozważałem nawet przejście na rubyforge, tylko po to, by przechowywać tam gotowe gemy, ale widać, że ten serwis jest dosyć kiepsko konserwowany, dlatego odszedłem od tego pomysłu.

Kiedy teraz okazało się, że github nie hostuje gemów (przynajmniej nowych gemów), to informację tę przyjąłem z pewną ulgą. Szukając jednak przyczyny stanu rzeczy, natknąłem się na post, w którym znalazło się zalecane rozwiązanie tej problematycznej sytuacji. Otóż twórcy githuba polecają serwis gemcutter.

Wygląda na to, że serwisy tworzone do realizacji jednego, specyficznego zadania stają się coraz bardziej popularne (niedawno np. github nie miał zakładki “issues”, która pozwala śledzić problemy związane z hostowanym projektem, zalecany był np. Lighthouseapp) – innymi słowy: idea SOA faktycznie zaczyna być realizowana, nie tylko w świecie javowym. Ale to temat na inny post.

Postanowiłem więc przetestować gemcuttera. Pierwsza rzecz, który musimy zrobić, aby zacząć go używać, to oczywiście zarejestrować się. I już na tym etapie byłem nieco zdziwiony, bo formularz rejestracyjny jest OLBRZYMI, choć zawiera tylko trzy pola :)

Po rejestracji powinniśmy zainstalować gem gemcutter, na lokalnej maszynie. Trzeba jednak wpierw upewnić się, czy mamy rubygems w wersji co najmniej 1.3.3:

$ gem -v 
1.3.1 # myślałem, że mam najnowsze rubygems...
$ gem update --system
Updating RubyGems
Updating rubygems-update
Successfully installed rubygems-update-1.3.5
...
$ gem -v
1.3.5 # uff
$ gem install gemcutter
...
Razem z gemem dostajemy nowe polecenia dla rubygems:
  • gem tumble – ustawia Gemcutter jako podstawowe źródło dla gemów (zamiast RubyForge)
  • gem push – wysyła gem na serwer Gemcutter
  • gem migrate – migruje gem wysłany wcześniej na RubyForge na Gemcutter
  • gem owner – włącza/wyłącza możliwość publikowanie przez innych twoich gemów

Z dyskusji, która pojawiła się na Rubyinside, wynika, że oficjalny hosting gemów może zostać przeniesiony z RubyForge na Gemcutter.

Ja w każdym razie zamierzać przetestować Gemcuttera – dzięki temu zarządzanie zależnościami między gemami będzie takie, jak być powinno :)

Na pierwszy ogień wziąłem mój gem colors.

$ gem build colors.gemspec
WARNING:  no rubyforge_project specified
  Successfully built RubyGem
  Name: colors
  Version: 0.0.4
  File: colors-0.0.4.gem
$ gem push colors-0.0.4.gem
Enter your Gemcutter credentials. Don't have an account yet? Create one at http://gemcutter.org/sign_up
Email:   apohllo@o2.pl
Password:   
Signed in. Your api key has been stored in ~/.gemrc
Pushing gem to Gemcutter...
Successfully registered gem: colors (0.0.4)

Mając w pamięci doświadczenia z githubem, gdzie po wrzuceniu gemu do repo, jego zbudowanie i pojawienie się w repo trwało kilkanaście minut, a często wiązało się z modyfikacją manifestu (brakujące pliki, etc.) bardzo miło zaskoczył mnie fakt, że w wynik wyszukiwania na stronie gemcutter dla terminu “colors” od razu zwrócił mój gem!

Postanowiłem więc sprawdzić, czy faktycznie jest widoczny przez rubygems:

$ sudo gem install colors
ERROR:  could not find gem colors locally or in a repository
$ sudo gem tumble
Thanks for using Gemcutter!
Your gem sources are now:
- http://gemcutter.org
- http://gems.rubyforge.org/
- http://gems.github.com
$ sudo gem install colors
Successfully installed colors-0.0.4
1 gem installed
Installing ri documentation for colors-0.0.4...
Installing RDoc documentation for colors-0.0.4...
$ irb
>> require 'colors'
=> true
>> puts "abc".hl
*abc* #wyboldowane :)

Zatem działa! Biorąc pod uwagę fakt, że wszystko (łącznie z tym postem), zajęło mi mniej niż godzinę, zamierzam używać Gemcuttera!

colors | gem | gemcutter | ruby | Opublikowano 11:06 06-10-2009. Ostatnia modyfikacja 12:06 10-12-2009 [apohllo] | Komentarze (0)

Cyc-console

Ten post z pewnością powinien mieć dłuższy wstęp, który, mam nadzieję uda mi się napisać niebawem. Otóż z pewnością powinienem napisać więcej o ontologii Cyc, bo bez tego narzędzie, które tutaj promuję nie wydaje się zanadto przydatne.

Gdyby jednak znalazł się ktoś, kto zna tę ontologię i co więcej – korzystał z wbudowanej weń konsoli, z pewnością uzna, że jest ona rodem z epoki przedpotopowej. Nie wspiera ona wielu zasadniczych koncepcji znanych choćby z konsoli Linuksa, a nawet najprostszych klawiszy specjalnych, takich jak <Home> i <End>.

Pracując nieustannie z Rubim i jego świetną konsolą irb z dodatkiem Wirble, stwierdziłem, że można by spróbować zrobić podobną konsolę dla Cyc-a. Zasadniczo powinna ona posiadać następujące własności:
  • sensownie reagować na <Home>, <End>, strzałki itp.
  • mieć wbudowaną historię poleceń
  • wspierać kolorowane terminale
  • sprawdzać ilość nawiasów, przed wysłaniem zapytania na serwer
  • wspierać autouzupełnianie poleceń i symboli Cyc.

Jakiś czas temu zabrałem się za jej tworzenie i okazało się, że stworzenie takiej konsoli na bazie irb nie jest specjalnie trudne. Oczywiście, to co powstało jest w fazie alfa – w obecnej chwili nie ma np. autouzupełniania, ale jest już historia poleceń (zapamiętywana pomiędzy uruchomieniami), no i wykorzystanie biblioteki readline pozwala używać klawisze specjalne w normalny sposób.

Dla wszystkich zainteresowanych – kod może być pobrany z github.com/apohllo/cyc-console lub z wykorzystaniem Rubygems:

$ sudo gem install apohllo-cyc-console

(Od wersji 0.0.5 wystarczy wpisać sudo gem install cyc-console).

W obu wypadkach wymagany jest gem apohllo-colors, o którym pisałem w poprzednim poście.

cyc | ruby | Opublikowano 05:42 06-10-2009. Ostatnia modyfikacja 12:44 08-10-2009 [apohllo] | Komentarze (0)

Pierwszy wpis

Coś małego na początek – colors – rozszerzenie klasy String o możliwość kolorowania. Działa oczywiście wyłącznie na terminalach zgodnych z ANSI, na pozostałych dostaniemy tekst wejściowy z dodatkiem “krzaków”.

Instalacja z wykorzystaniem rubygems jest banalna (pod warunkiem, że mamy wersję co najmniej 1.2.0 i github dodany do źródeł)

$ sudo gem install apohllo-colors

$ sudo gem install gemcutter
$ sudo gem tumble
$ sudo gem install colors

(Więcej o powodach przejścia na gemcutter. Upewnij się również, że masz Rubygems w wersji co najmniej 1.3.3)

Potem odpalamy konsolę irb i sprawdzamy czy wszystko działa jak trzeba:

require 'rubygems'
require 'colors'
"abc".hl #=> abc (wyboldowane, uwierzcie mi na słowo)
"abc".hl(:red) #=> abc (czerwone, j.w. :)
"ala ma kota ale nie ma psa".hl(:blue, "ma") 
#=> ala *ma* kota ale nie *ma* pas (wyróżnione słowa na niebiesko)

Sam w sobie projekt ten z pewnością nie robi dużego wrażenia, ale wykorzystuję go nagminnie. Każdy kto zetknął się z kolorowaną konsolą, wie jaka jest różnica pomiędzy jednolitym, czarnym, białym czy zielonym tekstem, a np. wyróżnionym znakiem zachęty.

Zapraszam do testowania.

colors | ruby | Opublikowano 18:39 14-07-2009. Ostatnia modyfikacja 12:44 08-10-2009 [apohllo] | Komentarze (0)