YOUTUBE.COM: Video ripper
Auf BashScripts.org findet man ein kleines Scriptchen, mit dem man sich per Shell Videos von Youtube downloaden kann. Das Skript konvertiert dann gleich in MPEG. Praktisch :-)
Posted at 11:00nachm. Okt. 06, 2006 by cetixx in Tipps | Kommentare [0]
VDR: VDR Media Client
Version 0.0.0.7 vom VDR Media Client gibts schon eine Weile, aber hab das praktische Programm grad erst entdeckt. Damit kann man VDR Aufnahmen oder Live TV auf den PC oder Laptop (Windows) streamen. Recht praktisch, wenn Frau im Wohnzimmer Lindenstrasse und Mann lieber Bud Spencer guggen will. Laptop geschnappt, WLAN angeschmissen und ab ins Schlafzimmer ;-)
Posted at 04:14nachm. Okt. 02, 2006 by cetixx in Tipps | Kommentare [0]
Volltextsuche mit PostgreSQL 8.1, Tsearch2 und UTF8
Update 14.03.2007: Für PostgreSQL 8.2 habe ich ein neues Tutorial erstellt: PostgreSQL 8.2, Tsearch2 und UTF8
Update 27.10.2006: Ich habe ein paar Sachen geändert/hinzugefügt. Ich gehe noch etwas genauer auf das PGCLIENTENCODING ein, das ziemlich wichtig ist. Seit PostgreSQL 8.1.5 scheint man auch den Tsearch2-Patch nicht mehr zu brauchen und ich benutze jetzt andere Stemmer-Library's.
Die
Tsearch2-Entwickler haben den UTF8-Support von Postgres 8.2 auf 8.1.x
rückportiert. D.h. UTF8 kann man nun auch unter 8.1.x einsetzen. Den
Patch findet man hier: tsearch2.82.tar.gz (Tsearch2 Entwicklerseite). Dieser ist aber mittlerweile auch wieder veraltet. Ich möchte aber doch noch darauf hingewiesen haben, falls jemand noch Versionen < 8.1.5 verwendet oder Probleme beim installieren hat. In diesem Fall könnte man es mit diesem Patch versuchen.
Gleich vorweg: Dieses Dokument ist "Work in
progress". Diese Installationsanweisung ist wohl nicht der Weisheits
letzter Schluss, aber man sollte damit eine Tsearch2 Installation
hinbekommen.
Tsearch2 ist eine Erweiterung zu PostgreSQL
speziell für die
Volltextsuche. Zunächst mal, muss man ein bißchen was kompilieren.
Gehen wir mal davon aus, das PostgreSQL schon vorher kompiliert worden
ist und gehen wir weiter davon aus, das wir Version 8.1.5 verwenden.
Den Sourcecode von Postgres haben wir nach /opt/source/postgres gelegt.
Dort drin gibt es ein contrib Verzeichnis in welches man
reinwechselt.
Hat man nun Postgres 8.1.5, kann man sich folgenden Abschnitt nach meiner momentanen Erkenntnis sparen. Am Besten weiterlesen ab "Dann wechseln wir in...". Die Postgres-Installation für 8.1.4 und UTF8 hat bei mir nur mit dem erwähnten Patch funktioniert. Holen wir uns also den UTF8 Patch für PostgreSQL 8.1.x herunter und legen ihn ins contrib-Verzeichnis:
cd /opt/source/postgres/contrib
wget http://www.sai.msu.su/%7Emegera/postgres/gist/tsearch/V2/tsearch2.82.tar.gz
tar xvfz tsearch2.82.tar.gz
Dann benennen wir das alte tsearch2-Verzeichnus um, und legen auf das neue Verzeichnis einen Softlink (das ist wichtig, sonst kompiliert das nachher nicht!):
mv tsearch2 tsearch2.wo_utf8_support
ln -s tsearch2.82 tsearch2
Dann wechseln wir in das Verzeichnis tsearch2. Zum
Kompilieren von tsearch2 gibt man in diesem Verzeichnis nun einfach
make
make install
ein. Damit das dann auch mit der deutschen Sprache alles etwas
besser funktioniert, müssen noch ein paar zusätzliche Dinge erledigt
werden, die wir gleich besprechen. Um zu überprüfen, ob die DB auch mit UTF8 Encoding angelegt wurde, connected man sich auf den Datenbankcluster per psql und läßt sich mit \l alle Datenbanken anzeigen (oder psql -l). Wenn in der letzten Spalte UTF8 steht, paßt's.
Als nächstes wechselt man in das Verzeichnis tsearch2/gendict. gendict
hilft beim Erstellen von Wörterbüchertemplates. Genauer gesagt, bietet
es Unterstützung für die Snowball Wortstämme. Und von dieser Site
brauchen wir erstmal zwei Dateien. Für Postgres 8.1.4 hatte ich bisher immer diese Dateien verwendet:
wget http://www.snowball.tartarus.org/algorithms/german/stem.c
wget http://www.snowball.tartarus.org/algorithms/german/stem.h
wget http://www.snowball.tartarus.org/algorithms/german/stem_UTF_8.c
wget http://www.snowball.tartarus.org/algorithms/german/stem_UTF_8.h
Hat man die stem_UTF_8.(c|h) runtergeladen, benennt man sie nun um in stem.c und stem.h.
Bei Postgres 8.1.4 habe ich nun in den Dateien alle Vorkommen von german_ISO_8859_1 durch german ersetzt. Bei Postgres 8.1.5 (stem_UTF_8.(c|h)) habe ich die Dateien unverändert gelassen. Nun folgenden Befehl ausführen:
Postgres 8.1.4:
./config.sh -n de -s -p german -i -v -c stem.c -h stem.h -C'Snowball stemmer for German'
Postgres 8.1.5:
./config.sh -n de -s -p german_UTF_8 -i -v -c stem.c -h stem.h -C'Snowball stemmer for German'
cd ../../dict_de
Nun müßte man eigentlich mit make alle kompilieren. Neuerdings fliegt mir aber immer das Teil um die Ohren und behauptet, die Methode german_UTF_8_close_env hätte ein Argument zu viel. Deshalb ändere ich die Zeile (ganz unten in der Datei stem.c):
extern void german_UTF_8_close_env(struct SN_env * z) { SN_close_env(z, 0); }
in
extern void german_UTF_8_close_env(struct SN_env * z) { SN_close_env(z); }
Dann kann man den make starten:
make
make install
Es fliegen einem dann zwar ein paar Warnings um die Ohren, aber die scheinen nicht weiter schlimm zu sein. Wenn das dann passiert ist, landet die dict_de.so im PostgreSQL
lib Verzeichnis. Ab hier ist dann für alle Postgres-Versionen alles gleich. Ich schreib das hier nur alles auf, damit es jemanden vielleicht weiterhilft. Das scheint aber bei jedem anders zu sein...
Als nächstes muß man jetzt erstmal die Datenbank für tsearch2 und das Wortstammbuch vorbereiten und das funkt, in dem man zwei SQL-Skripte einspielt als PostgreSQL Superuser (die muß man natürlich vorher rüberspielen):
Die Datei contrib/tsearch2/tsearch2.sql sollte man sich vorher nochmal anschauen und eventl. in der ersten Zeile den search_path anpassen. Dann:
psql -d dbname -f tsearch2.sql
Die Datei contrib/dict_de/dict_de.sql sollte man sich ebenfalls vorher nochmal anschauen und eventl. in der ersten Zeile den search_path anpassen. Dann:
psql -d dbname -f dict_de.sql
Da nun vier Tabellen als Superuser angelegt worden sind, aber man i.d.R. ja eher unter einem "normalen" Account mit weniger Rechten arbeitet, muss man nun diesem User erlauben, das er diese Tabellen bearbeiten darf:
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_cfg TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_cfgmap TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_dict TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_parser TO [USER];
SCHEMA kann man weglassen, wenn man sowieso alles im public Schema hat. Ansonsten gibt man halt noch den Schema-Namen davor an. So... Nun kann man sich mal unter dem User einloggen, unter dem man alles installiert hat. Folgender Befehl sollte dann unter psql schon klappen:
db=> SELECT 'Our first string used today'::tsvector;
Hier sieht man dann schon, dass der übergebene String in seine Einzelteile zerlegt wird. Als Nächstes probieren wir mal Folgendes aus:
db=> SELECT * FROM ts_debug('Our first string used today');
ERROR: could not find tsearch config by locale
CONTEXT: SQL function "_get_parser_from_curcfg" statement 1
SQL function "ts_debug" during startup
Dieser Fehler (wobei es ja eigentlich kein Fehler im eigentlichen Sinne ist, sondern ein Konfigurationsfehler meinerseits) hätte mich fast zur Weißglut getrieben. Guggen wir mal in die Konfiguration:
db=> SELECT * FROM pg_ts_cfg;
ts_name | prs_name | locale |
default | default | C |
default_russian | default | ru_RU.KOI8-R |
simple | default |
Da sehen wir, das als Locale C als Default (Spalte ts_name, Eintrag default) verwendet wird. Geben wir unter psql dann mal folgende Befehle ein:
db=> SHOW lc_ctype;
lc_ctype
de_DE.utf8@euro
(1 Zeile)
db=> SHOW lc_collate;
lc_collate
de_DE.utf8@euro
(1 Zeile)
In meinem Fall also de_DE.utf8@euro. Und in der Konfigurationstabelle steht davon natürlich noch nicht's. Man muß also für das Server-Locale eine entsprechende Konfiguration erstellen. Wenn ich das richtig verstanden habe, dann sollte das Locale hier das sein, was man beim Initialisieren des Postgres-Clusters beim initdb als Paramter --locale mitgegeben hat. Gehen wir's also an...
Zunächst brauchen wir erstmal ein paar Dateien. Die muß man normalerweise selber generieren, aber ich hab sie mal zusammengepackt:
tsearch2_utf8_required_files.tar.gz
Darin enthalten sind u.a.: german.aff (hiermit wird es möglich, die zusammengesetzten Wörter sog. compound words aufzulösen, also z.B. Tischkante), german.med (das Wörterbuch an sich), german.stop und german.stop.ispell (zwei mögliche Dateien mit Stopwörtern also "der, die, das, usw.". Dann zu suchen, macht wenig Sinn...). Die Dateien reichen erstmal um weiter zu machen. Man kopiert die Dinger am Besten irgendwo hin, wo Postgres Zugriff hat. Das konvertieren an sich, ist auch nicht allzu schwer, wenn man's selber machen will. Wenn man die entsprechenden Dateien im Latin1-Encoding schon hat, konvertiert man sie einfach wie folgt:
iconv -f iso-8859-1 -t utf-8 -o german_utf8.med german.med
iconv -f iso-8859-1 -t utf-8 -o german_utf8.aff german.aff
iconv -f iso-8859-1 -t utf-8 -o german_utf8.stop german.stop
iconv -f iso-8859-1 -t utf-8 -o german_utf8.stop.ispell german.stop.ispell
Da ich auch noch Datenbanken mit Latin1 Encoding habe, gibt es bei mir zwei Unterordner - einen für die Dateien mit Latin1 Encoding und die anderen eben für UTF8.
Damit wir nun eine funktionsfähige Tsearch2 Konfiguration bekommen, sind noch ein paar weitere SQL-Statements notwendig. Zunächst benennen wir den default-Tsearch2-Eintrag mal um, da wir ja unseren eigenen verwenden wollen:
UPDATE pg_ts_cfg SET ts_name='default_c' WHERE prs_name='default' AND locale='C';
Dann fügen wir unsere Defaults ein:
db=> INSERT INTO pg_ts_cfg(ts_name, prs_name, locale) VALUES('default', 'default', 'de_DE.utf8@euro');
Bevor man nun weitermacht, sollte man noch das richtige Clientencoding einstellen. Das dürfte i.d.R. LATIN1 sein, wenn man auf der Shell arbeitet und ist für später wichtig, wenn wir die Testquery ausführen wollen. Das Clientencoding setzt man auf der Shell mit
export PGCLIENTENCODING=LATIN1
Wenn euch Meldungen wie
ERROR: invalid byte sequence for encoding "UTF8": 0xe4fcf6
oder
ERROR: Affix parse error at 644 line
um die Ohren fliegen, liegt das mit gaaaaanz hoher Wahrscheinlichkeit an einem falsch eingestellten Encoding. Bei PostgreSQL 8.1.5 sind die Meldungen etwas genauer. Bei letzterer Meldung war z.B. das Encoding der german_utf8.aff Datei kein "echtes" UTF8. Bei der ersten Meldung hab ich auf der psql-Shell gearbeitet und unten stehende Testquery ausgeführt, die Umlaute enthielt. Also immer mal auf das Encoding aufpassen!
Dann fügen wir mal die entscheidenste Konfiguration ein:
db=> INSERT INTO pg_ts_dict
(SELECT 'de_ispell', dict_init,
'DictFile="/data/pgsql/share/dict/utf8/german_utf8.med",'
'AffFile="/data/pgsql/share/dict/utf8/german_utf8.aff",'
'StopFile="/data/pgsql/share/dict/utf8/german_utf8.stop.ispell"',
dict_lexize
FROM pg_ts_dict
WHERE dict_name = 'ispell_template');
Dann stellen wir ein, welches Wörterbuch wir verwenden wollen:
db=> SELECT set_curdict('de_ispell');
oder
db=> SELECT set_curdict(DIE_NUMMER_DIE_DER_VORHERGEHNDE_INSERT_AUSSPUCKT);
Ich habe festgestellt, das letzter Befehl beim Debuggen gar nicht so schlecht ist, da er wesentlich mehr Info's ausspuckt. Als nächstes müssen wir dann noch angeben, für welche Wörter wir welches Wörterbuch verwenden wollen:
db=> DELETE FROM pg_ts_cfgmap WHERE ts_name='default' AND dict_name='{en_stem}';
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default', 'lhword', '{de_ispell,simple}');
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default', 'lpart_hword', '{de_ispell,simple}');
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default', 'lword', '{de_ispell,simple}');
Bei dem Delete sollten drei Einträge rausfliegen. {de_ispell,simple} besagt, das wir zunächst das ISpell-Wörterbuch verwenden wollen und dann das Simple-Wörterbuch. Ohne das Simple-Wörterbuch würde das Suchergebnis erheblich kleiner sein und viele einfache Wörter würden aussen vor bleiben. Ein noch besseres Ergebnis dürften die OpenOffice-Wörterbücher bringen. Das muss ich bei Gelegenheit mal ausprobieren. Wenn das durchgelaufen ist, kann man mal folgende Testquery absetzen:
db=> select to_tsvector('PostgreSQL ist weitgehend konform mit dem SQL92/SQL99-Standard, d.h. alle in dem Standard geforderten Funktionen stehen zur Verfügung und verhalten sich so, wie vom Standard gefordert; dies ist bei manchen kommerziellen sowie nichtkommerziellen SQL-Datenbanken bisweilen nicht gegeben.');
to_tsvector
* 'all':9 'bei':28 'd.h':8 'dem':6,11 'die':26 'ist':2,27 'mit':5 'sql':34 'und':18 'vom':23 'wie':22 'zur':16 'sich':20 'sowi':31 'nicht':37 'stehen':15 'gegeben':38 'konform':4 'manchen':29 'standard':12,24 'bisweilen':36 'gefordert':25 'verfügung':17 'verhalten':19 'funktionen':14 'postgresql':1 'weitgehend':3 'datenbanken':35 'geforderten':13 'kommerziellen':30 'sql-datenbanken':33 'nichtkommerziellen':32 'sql92/sql99-standard':7
(1 Zeile)
Man sieht also hier jetzt, wie Tsearch2 den String zerlegt hat. Die Nummern dahinter sind die Positionen der Wörter im Text. So... Soweit wären wir nun also schon. Aber wir wollen natürlich nicht nur in einem Satz nach bestimmten Wörtern suchen, sondern in der Datenbank bzw. eben in verschiedenen Spalten. Nehmen wir als Beispiel eine Installation von der bekannten Forumsoftware phpBB. Dort gibt es eine Tabelle phpbb_posts_text (wenn man als Prefix bei der Installation phpbb belassen hat) die wiederum eine Spalte post_text hat. Diese Spalte ist vom Typ text. Da landen die Postings der User drin und da kann schon mal längerer Text werden. Und genau da drin wollen wir suchen können. Zunächst fügen wir dieser Tabelle eine neue Spalte hinzu:
db==> ALTER TABLE phpbb_posts_text ADD COLUMN idxfti tsvector;
Anstatt wie bei "normalen" Indizies "hängt" dieser Index soz. an der Tabelle dran. Diese Spalte kann dann durch die Tsearch2 Operatoren und Funktionen und durch einen speziellen Index zur Volltextsuche genutzt werden. Diese Spalte heißt in diesem Fall idxfti. Es gibt einen Grundsatz, denn man einhalten sollte, wenn man einen Volltextindex erzeugt:
1. Tabelle befüllen
2. VACUUM FULL ANALYZE tablename;
3. Index erzeugen
4. VACUUM FULL ANALYZE tablename;
db==> UPDATE phpbb_posts_text SET idxfti=to_tsvector('default', post_text);
db==> VACUUM FULL ANALYZE phpbb_posts_text;
Der Funktion to_tsvector sagen wir hier, das wir die default Konfiguration verwenden wollen (die haben wir oben ja auf die deutschen Wörterbücher eingestellt) und das wir die Spalte post_text indizieren wollen. Möchte man mehrere Spalten indizieren, sieht das so aus:
db==> UPDATE phpbb_posts_text SET idxfti=to_tsvector('default',coalesce(post_text,'') ||' '|| coalesce(post_subject,''));
Nun erzeugen wir den eigentlichen Index:
db==> CREATE INDEX idxfti_idx ON phpbb_posts_text USING gist(idxfti);
Nun brauchen wir noch einen Trigger, der uns den Index auf den neuesten Stand hält, sobald ein neuer Eintrag hinzukommt:
db==> CREATE TRIGGER idxftiupdate BEFORE UPDATE OR INSERT ON phpbb_posts_text
db==> FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxfti, post_text);
Wenn man oben zwei Spalten für die Indizierung angegeben hat, sieht der Trigger etwas anders aus:
db==> CREATE TRIGGER idxftiupdate BEFORE UPDATE OR INSERT ON phpbb_posts_text
db==> FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxfti, post_text, post_subject);
Die Funktion tsearch2 akzeptiert mehrere Argumente, so das man hier die beiden Spalten nicht verknüpfen muss. Und dann war's dann auch schon... Jetzt kann man Abfragen starten bzw. man kann sich auch die Inhalte der Tabelle selber anschauen. Die neue Spalte enthält nämlich z.B. die gefundenen Wörter.
Beispielquery's:
Einfache Suche:
SELECT post_text FROM phpbb_posts_text WHERE idxfti @@ to_tsquery('default', 'haus');
Suche mit UND:
SELECT post_text FROM phpbb_posts_text WHERE idxfti @@ to_tsquery('default', 'haus & garten');
Suche mit ODER:
SELECT post_text FROM phpbb_posts_text WHERE idxfti @@ to_tsquery('default', 'haus | garten');
Links zum Thema:
Implementing Full Text Indexing with PostgreSQL
http://www.devx.com/opensource/Article/21674/0/page/3
Tsearch2 - Introduction
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/tsearch-V2-intro.html
Tsearch2 and Unicode/UTF-8 - German Unicode Datebase
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/tsearch2_german_utf8.html
Gendict - generate dictionary templates for contrib/tsearch2 module
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/README.gendict
Deutsche Ispell Stop-Datei
http://hannes.imos.net/german.stop.ispell
German stemming algorithm
http://www.snowball.tartarus.org/algorithms/german/stemmer.html
Deutsche Wörterbuch und Stop-Dateien
http://www.computec.de/dload/tsearch2_german_utf8.zip
Can't find tsearch config by locale
http://blog.gmane.org/gmane.comp.db.postgresql.openfts.general/month=20040801
USING TSEARCH AND POSTGRESQL FOR A WEB BASED SEARCH ENGINE
http://www.sai.msu.su/~megera/postgres/gist/tsearch/tsearch-intro.html
Tsearch V2 Notes
http://www.sai.msu.su/~megera/oddmuse/index.cgi/Tsearch_V2_Notes
Tsearch V2 Optimization
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/oscon_tsearch2/optimization.html
Tsearch V2 compound words
http://www.sai.msu.su/~megera/oddmuse/index.cgi/Tsearch_V2_compound_words
TSearch2 / German compound words / UTF-8
http://archives.postgresql.org/pgsql-general/2005-11/msg01113.php
Posted at 12:00vorm. Aug. 23, 2006 by cetixx in Tipps | Kommentare [0]
Dawicontrol DC-154 und Linux
Wer auf der Suche nach einem einfachen SATA-Controller ist, der auch unter Linux läuft, sollte sich den Dawicontrol DC-154 mal ansehen. Läuft bei mir jetzt mit zwei 300 GB Samsungplatten ohne Murren. Außerdem bringt man insgesamt 4 Platten dran. Der Controller arbeitet mit dem Silicon Image Chip Si 3114. Der Kernel sollte allerdings schon neueren Datums sein. Bei mir ist es der 2.6.15 der bei Ubuntu 6.06 dabei war. Ein Performancewunder darf man bei diesem Controller natürlich nicht erwarten, aber bei mir war die Devise nur: VIEL PLATZ ;-) |
&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; |
Posted at 10:00nachm. Aug. 14, 2006 by cetixx in Tipps | Kommentare [1]
ORACLE: Versteckte Parameter anzeigen
Es gibt ja in Oracle diese wundersamen hidden parameter, wo alle total geil drauf sind, weil wenn man die ändert, das System plötzlich fliegt... (Naja... Wer's glaubt ;-) Querytuning dürfte in 99% der Fälle mehr bringen...). Man kommt hin und wieder in die Bedrängnis rauszufinden, welchen Wert den so ein Paramter hat (die mit dem _ beginnend). SHOW PARAMETER oder v$parameter zeigt die Dinger (aus gutem Grund) unverschämterweise nicht an. Aber man kann sich mit folgender Query behelfen:
SELECT
a.ksppinm "Parameter",
b.ksppstvl "Session
Value",
c.ksppstvl "Instance Value"
FROM x$ksppi a, x$ksppcv b, x$ksppsv c
WHERE a.indx = b.indx AND a.indx
= c.indx AND a.ksppinm LIKE '/_%' escape '/' ORDER BY a.ksppinm;
Beschrieben wird das in Oracle Metalink Note 315631.1.
Posted at 08:00nachm. Aug. 11, 2006 by cetixx in Tipps | Kommentare [0]
VDR: Streamdev Plugin + VLC 0.8.5
Wer bisher immer Probleme hatte, mit VLC vom VDR über das Streamdev Plugin einen Stream abzugreifen und dabei den Videostream, aber leider keinen Ton hatte, dem kann geholfen werden! VLC 0.8.5 ist die Lösung. Diese Version ist seit kurzer Zeit draussen und spielt nun endlich auch Ton ab ohne irgendwelche Spezialkonstrukte.
Wer sich für den VLC noch eine Sender-Playliste automatisch erstellen lassen möchte, findet in diesem Forumseintrag auf vdr-portal.de Entsprechendes.
Posted at 02:00nachm. Juni 04, 2006 by cetixx in Tipps | Kommentare [0]
DEBIAN 3.1: Update auf Kernel 2.6.16
Ja, ja... Manchmal tut man Dinge, die man lieber nicht hätte tun sollen, aber dann doch noch einigermaßen glimpflich abgelaufen sind. Gestern kam ich auf die komische Idee, ich müßte meinen Kernel 2.6.12-ct-1 auf den 2.6.16-1-k7 von backports.org updaten. Meine Hoffnung war/ist, das sich die Systemstabilität etwas erhöht. Zwischen 2.6.8 und 2.6.12 war schon eine deutliche Besserung zu vermerken.
Nun. Nachdem ich gesehen habe, das backports.org auch einen Kernel 2.6.16-1-xen-k7 zur Verfügung stellt und ich Xen schon immer mal testen wollte, hab ich den Kernel installiert. Das das Update nicht so einfach wird, war fast klar, da ja z.B. Hotplug durch udev ersetzt wurde und damit z.B. die Technotrend/Nexus TV-Karten nicht mehr auf Anhieb funktionieren. Nun gut. Also apt-get aufgerufen und Kernel installiert. Bei den zu deinstallierenden Paketen stand der Bootloader Grub dabei. Wieso will der Grub deinstallieren? Dafür soll dann Lilo drauf. Hmmm... Naja. Was soll's. Also akzeptiert und der Download startet. Ging alles soweit, bis liloconfig aufgerufen wurde. Das meinte dann, dass es /dev/hda1 nicht findet und den Bootloader nicht installieren kann. Ah ja... Das ist toll. Nun ja. Diesen Schritt also übersprungen und die Grub-Konfig angepaßt. Nur komisch, das es unter /boot kein initrd File gibt. Tja blöd. Kein initrd und Lilo will nicht. Downgrade wollte ich auch nicht mehr machen, da das Kernelupdate soviele andere Pakete upgedatet hat, das ich mich nicht mehr getraut habe, den Downgrade durchzuführen. Also Rechner nochmal mit dem alten Kernel durchgestartet. Das ging zum Glück gut. Dann also nochmal liloconfig aufgerufen. Diesmal kam dann die Meldung, das er Lilo nicht installieren kann, da das Image zu groß ist. Ok. Jetzt reichts.
Xen-Kernel raus, 2.6.16-1-k7 rein. Grub Config läuft dieses mal automatisch. Rechner durchgestartet. Läuft. Blos die TV-Karten funken nicht mehr. Er lädt alle Module und was man sonst so braucht, initialisiert aber den Karte nicht. Also unter vdr-portal.de gesucht. Die meisten Lösungen waren aber für Hotplug. Das ist aber mit ab Kernel 2.6.15 eigentlich obsolet. udev ist zunächst mal die Zukunft (fragt sich blos wie lange...). Also entsprechend gepostet. Der entscheidende Hinweis war dann, das stradis-Modul zu entfernen und das Modul unter /etc/modprobe.d/blacklist einzutragen, damit es nicht mehr automatisch geladen wird. Und schon funkte dann auch der TV-Kartentreiber wieder. Feini fein :-)
Die Sache mit Lilo und Xen war recht ärgerlich. Der erste Eindruck vom "normalen" 2.6.16 ist recht positiv. Das Paketmanagement und der Kernel ohne Xen von backports.org funktionieren recht gut. Scheint alles recht rund zu laufen.
Posted at 01:00vorm. Juni 02, 2006 by cetixx in Tipps | Kommentare [0]
POSTGRESQL: Migration Oracle / Postgres
Oracle und Postgres sind sich in so mancher Hinsicht recht ähnlich. Darum sieht man jetzt auch viele Projekte, in denen von Oracle zu Postgres migriert wird. Für viele Anwendungen ist Postgres mehr als ausreichend. Nun... Entsprechend vorbereitet, klappt das auch recht gut, wenn einem nicht ein bestimmtes Datentypen/Index-Problem um die Ohren fliegt und das beim Lasttest dann auch nicht auffällt, weil man genau die URL zufälligerweise nicht getestet hat ;-)
Das sieht dann z.B. so aus:
test=> EXPLAIN SELECT * FROM tab1 JOIN tab2 ON tab2.rel2objects=tab1.relation_id WHERE tab2.oid=7929;
QUERY PLAN
Hash Join (cost=4.11..42522.51 rows=64 width=573)
Hash Cond: (("outer".relation_id)::text = ("inner".object_assign)::text)
-> Seq Scan on tab3 (cost=0.00..34034.29 rows=1131129 width=77)
-> Hash (cost=4.11..4.11 rows=1 width=496)
-> Index Scan using idx_tab2 on tab2 (cost=0.00..4.11 rows=1 width=496)
Index Cond: (oid = 7929)
(6 rows)
Der Hash Join (was mehr oder weniger ein Full Table Scan ist) zeigt es schon: Die Datenbank erwartet Kosten zwischen 4.11 und 42522.51 und beim Seq. Scan sehen wir das über 1,1 Mio. Datensätze durchgegrast werden. Für eine Webapplikation nicht so ganz gut. Und warum ist das so? Wir haben doch entsprechende Indizies, aber die DB nimmt sie nicht her! Hmmm... Bei Oracle war der Execution Plan einwandfrei. Bauen wir die Query mal wie folgt um:
test=> EXPLAIN SELECT * FROM tab1 JOIN tab2 ON tab2.rel2objects::integer=rel_o.relation_id WHERE tab2.oid=7929;
QUERY PLAN
Nested Loop (cost=0.00..13.53 rows=18 width=573)
-> Index Scan using idx_tab2 on tab2 (cost=0.00..4.11 rows=1 width=496)
Index Cond: (oid = 7929)
-> Index Scan using idx_tab1 on tab1 (cost=0.00..9.15 rows=18 width=77)
Index Cond: (("outer".object_assign)::integer = tab3.relation_id)
(5 rows)
Alles was ich geändert habe, ist der Integer-Cast (... tab2.rel2objects::integer=...). Der Witz an der Sache ist, das rel2objects vom Datentyp Varchar ist und relation_id ist ein Integer. Damit werden für Postgres die Indizies wertlos. Ein expliziter Cast tut Not. Und wie man sieht, ist der Ausführungsplan nun schon erheblich besser. Oracle hat die gleiche Query hingegen ganz anders behandelt. Das Casten war hier kein Thema. Die Oracle bekommt allerdings die totale Krise, wenn die Optimizer Statistiken nicht stimmen. Das stört die Postgres nicht so stark. Allerdings wird diese wiederum sauer, wenn die Datentypen beim Join nicht exakt stimmen. Auch int, int4 und int8 sind für die Postgres nicht gleich und würde auch hier eventl. vorhandene Indizies nicht verwenden. Es hilft also nur, den Ausführungsplan zu checken, um sich vor bösen Überraschungen bei der Migration einigermaßen zu schützen.
Posted at 12:00vorm. Mai 30, 2006 by cetixx in Tipps | Kommentare [0]
last.fm
Also wer heute noch Lieder bei Donkey & Co. runterlädt, der ist selber Schuld. Es gibt doch so ein wunderbares Internetradio, das sich da last.fm nennt. Das ist ein mehr oder weniger personalisiertes Radio. Man meldet sich einfach an und wählt eine Gruppe/Sänger bzw. Musicrichtung aus und drückt soz. einfach Play. Dann legt der Player (es gibt auch Plugins für jede Menge Player) los und streamt in 128 KBit/s Musik als MP3 runter. Und was da kommt, entspricht der Musikrichtung die man da angegeben hat. Ist man z.B. ein Fan von U2 oder Queen, dann spielt der Player Songs, die dazu verwandt sind. Das Ganze ohne Werbung, Moderation und sauber getrennt.
Und das Beste ist, das es ein wunderbares Perl-Skript gibt, das sich beim Radio anmeldet und das Ganze dann auf Platte speichert. Und das absolut genau! Kein anschließendes schneiden mehr wie bei anderen Radiostationen. Ich finds ziemlich gut...
Posted at 11:00nachm. Apr. 06, 2006 by cetixx in Tipps | Kommentare [0]
*NIX: Terminal-Fenster zerschossen
Wenn man mal wieder eine binäre Datei mit cat angeguggt hat, kommt es schon mal vor, das das Terminalfenster nur noch komische Zeichen anzeigt. Entweder schließt man das Fenster nun oder man gibt (blind) reset ein. Das sollte helfen.
Posted at 12:00vorm. Apr. 05, 2006 by cetixx in Tipps | Kommentare [0]
JMETER: java.rmi.ConnectException: Connection refused to host: 127.0.0.1
Das ansonsten gute Stresstool Apache Jakarta JMeter kann einen manchmal in den Wahnsinn treiben. Probleme gibts zum Einen wenn man hinter einer Firewall sitzt mit dem GUI und mehrere Server "dahinter" hat. Da kann dann RMI keinen Callback durch die Firewall zur GUI machen kann. Oder wenn man auf dem/den Server(n) unterschiedliche Java Versionen verwendet, dann kann es auch zu Problemen mit RMI kommen.
Und dann gibts immer wieder mal java.rmi.ConnectException: Connection refused to host: 127.0.0.1 wenn man im jmeter.log guggt und ebenfalls oben beschriebenes Szenario hat. Mit manchen Servern kann das GUI reden und bei Anderen kommt die Connection refused Meldung. Nun diese Meldung kommt daher, da der Aufruf
InetAddress.getLocalHost().getHostName()
im JMeter Code auf der Serverseite einfach "127.0.0.1" zurückliefert. Der Server sagt also zum GUI: "Hör mal: Du kannst mich unter 127.0.0.1 erreichen" - was natürlich nicht der Fall ist... Man muss also mal in die /etc/hosts guggen, ob da nicht der Servername hinter der 127.0.0.1 steht. Hier sollte statt dessen die IP stehen, unter der das GUI den Server wirklich erreichen kann.
Ein kleines Testprogramm in Java, was o.g. Aufruf zurückgibt:
import java.net.*;
class GetHostName {
public static void main(String[] args) {
try {
System.out.println(InetAddress.getLocalHost().getHostName());
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Siehe auch: Remote Testing Trouble
Posted at 11:00nachm. Apr. 04, 2006 by cetixx in Tipps | Kommentare [0]
Volltextsuche mit PostgreSQL und Tsearch2
UPDATE 2006-08-22: Ich habe eine neue Anleitung geschrieben. Wer UTF8 als DB Encoding verwendet, sollte diese Anleitung verwenden: Volltextsuche mit PostgreSQL 8.1.x, Tsearch2 und UTF8.
UPDATE 2006-04-24: Die
Tsearch2-Entwickler haben den UTF8-Support von Postgres 8.2 auf 8.1.3
rückportiert. D.h. UTF8 kann man nun auch unter 8.1.3 einsetzen. Den
Patch findet man hier: tsearch2.82.tar.gz (Tsearch2 Entwicklerseite). Ich hab den Text an den entsprechenden Stellen angepaßt. Bisher bin ich ja davon ausgegangen, das die Volltextsuche mit einer Latin1 Datenbank installiert wird.
Gleich vorweg: Dieses Dokument ist "Work in progress". Diese Installationsanweisung ist wohl nicht der Weisheits letzter Schluss, aber man sollte damit eine Tsearch2 Installation hinbekommen.
Tsearch2 ist eine Erweiterung zu PostgreSQL speziell für die
Volltextsuche. Zunächst mal, muss man ein bißchen was kompilieren.
Gehen wir mal davon aus, das PostgreSQL schon vorher kompiliert worden
ist und gehen wir weiter davon aus, das wir Version 8.1.3 verwenden. Den Sourcecode von Postgres haben wir nach /opt/source/postgres gelegt. Dort drin gibt es ein contrib/tsearch2 Verzeichnis in welches man reinwechselt. Wenn man den UTF8 Tsearch2-Patch runtergeladen und in entsprechenden Verzeichnis entpackt hat, dann wechelt man nach tsearch2.82 rein. Wichtig hierbei ist, das das Verzeichnis entweder in tsearch2 umbenannt oder einen Softlink drauf gelegt wird, sonst fliegen einem nachher beim Kompilieren ein paar Sachen um die Ohren. Zum Kompilieren von tsearch2 gibt man in diesem Verzeichnis nun einfach
make
make install
ein. Damit das dann auch mit der deutschen Sprache alles etwas
besser funktioniert, müssen noch ein paar zusätzliche Dinge erledigt
werden. Das ist zum großen Teil hier beschrieben, aber bei mir hat das so nicht ganz funktioniert. Soweit
ich das in den Mailinglisten gelesen habe, unterstützt Tsearch2
momentan noch gar kein UTF8 in der Version 8.1.(0-2) von PostgreSQL. Das soll
erst mit der 8.2er offiziell funken. Für die 8.1.3 gibt es den o.g. Patch. Die vorher genannte
Seite geht jedenfalls davon aus, das die Datenbank UTF8/Unicode als
Encoding verwendet. Damit funktioniert aber die Library mit den
Wortstämmen nicht. Diese hat nämlich gar keine Methode für UTF8 sondern
nur für Latin1 bzw. eben ISO8859-1. Deshalb gehe ich jetzt davon aus,
das die Datenbank mit Encoding Latin1/ISO8859-1 erstellt worden ist. Um
das zu überprüfen, connected man sich auf den Datenbankcluster per psql und läßt sich mit \l alle Datenbanken anzeigen. Wenn in der letzten Spalte LATIN1 steht, paßt's. Hat man Version 8.1.3 mit o.g. Patch installiert, kann man auch UTF8/UNICODE als Datenbankencoding verwenden. Mehr dazu weiter unten.
Als nächstes wechselt man in das Verzeichnis tsearch2/gendict. gendict hilft beim Erstellen von Wörterbüchertemplates. Genauer gesagt, bietet es Unterstützung für die Snowball Wortstämme. Und von dieser Site brauchen wir erstmal zwei Dateien:
wget http://www.snowball.tartarus.org/algorithms/german/stem.c
wget http://www.snowball.tartarus.org/algorithms/german/stem.h
Die in der obigen Doku beschriebenen Links sind inzwischen veraltet. Als nächstes ruft man folgenden Befehl auf:
./config.sh -n de -s -p german_ISO_8859_1 -i -v -c stem.c -h stem.h -C'Snowball stemmer for German'
Und das ist genau der Gag an der Sache. In obiger Doku steht nur -p german als Option. Das config funkt zunächst, aber beim kompilieren nachher fliegt einem das um die Ohren, weil er eine bestimmte Methode nicht findet. Wenn man nämlich mal in die stem.c reinguggt, dann sieht man da ganz oben gleich die Zeile
extern int german_ISO_8859_1_stem(struct SN_env * z);
Und genau das muss man bei der -p Option angeben, aber ohne das _stem hinten. Also falls es da mal beim anschließenden make; make install Probleme gibt, prüft das vorher mal. Von Mathias Behrle (siehe Kommentare unten) kam noch der Tipp, in den Dateien stem.c und stem.h german_ISO_8859_1 einfach durch german zu ersetzen. Das scheint auch zu funktionieren. Das bietet sich bei Verwendung von UTF8 als Datenbankencoding wohl auch an, da das irgendwie mit dem ISO_8859_1 nicht so gut zusammenpaßt (optisch gesehen ;-)). Der config-Befehl sieht dann so aus:
./config.sh -n de -s -p german -i -v -c stem.c -h stem.h -C'Snowball stemmer for German'
Wenn config durchgelaufen ist, wechselt man in ein anderes Verzeichnis:
cd ../../dict_de/
make
make install
Wenn das passiert ist, landet die libdict_de.so im PostgreSQL lib Verzeichnis. Als nächstes muß man jetzt erstmal die Datenbank für tsearch2 und das Wortstammbuch vorbereiten und das funkt, in dem man zwei SQL-Skripte einspielt als PostgreSQL Superuser (die muß man natürlich vorher rüberspielen):
Die Datei contrib/tsearch2/tsearch2.sql sollte man sich vorher nochmal anschauen und eventl. in der ersten Zeile den search_path anpassen. Dann:
psql -d dbname -f tsearch2.sql
Die Datei contrib/dict_de/dict_de.sql sollte man sich ebenfalls vorher nochmal anschauen und eventl. in der ersten Zeile den search_path anpassen. Dann:
psql -d dbname -f dict_de.sql
Da nun vier Tabellen als Superuser angelegt worden sind, aber man i.d.R. ja eher unter einem "normalen" Account mit weniger Rechten arbeitet, muß man nun diesem User erlauben, das er diese Tabellen bearbeiten darf:
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_cfg TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_cfgmap TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_dict TO [USER];
GRANT select,insert,update,delete ON [SCHEMA].pg_ts_parser TO [USER];
SCHEMA kann man weglassen, wenn man sowieso alles im public Schema hat. Ansonsten gibt man halt noch den Schema-Namen davor an. So... Nun kann man sich mal unter dem User einloggen, unter dem man alles installiert hat. Folgender Befehl sollte dann unter psql schon klappen:
db=> SELECT 'Our first string used today'::tsvector;
Hier sieht man dann schon, dass der übergebene String in seine Einzelteile zerlegt wird. Als Nächstes probieren wir mal Folgendes aus:
db=> SELECT * FROM ts_debug('Our first string used today');
ERROR: could not find tsearch config by locale
CONTEXT: SQL function "_get_parser_from_curcfg" statement 1
SQL function "ts_debug" during startup
Dieser Fehler hätte mich fast zur Weißglut getrieben. Guggen wir mal in die Konfiguration:
db=> SELECT * FROM pg_ts_cfg;
ts_name | prs_name | locale |
default | default | C |
default_russian | default | ru_RU.KOI8-R |
simple | default |
Da sehen wir, das als Locale C als Default (Spalte ts_name, Eintrag default) verwendet wird. Geben wir unter psql dann mal folgende Befehle ein:
db=> SHOW lc_ctype;
lc_ctype
de_DE.iso88591
(1 Zeile)
db=> SHOW lc_collate;
lc_collate
de_DE.iso88591
(1 Zeile)
In meinem Fall also de_DE.iso88591 oder auch LATIN1 genannt. Und in der Konfigurationstabelle steht davon natürlich noch nicht's. Man muß also für das Server-Locale eine entsprechende Konfiguration erstellen. Wenn ich das richtig verstanden habe, dann sollte das Locale hier das sein, was man beim Initialisieren des Postgres-Clusters beim initdb als Paramter --locale mitgegeben hat. Gehen wir's also an...
Zunächst brauchen wir erstmal ein paar Wörterbücher. Die muß
man normalerweise selber generieren, aber man kann sie auch hier
downloaden:
http://www.computec.de/dload/tsearch2_german_utf8.zip
Darin enthalten sind u.a.: german.aff, german.med, german.stop und german.stop.ispell. Die Dateien reichen erstmal um weiter zu machen. Man kopiert die Dinger am Besten irgendwo hin, wo Postgres Zugriff hat. Als Nächstes brauchen wir einen Eintrag in der Konfigurationstabelle für die Wortstämme z.B.:
db=> UPDATE pg_ts_dict
db=> SET dict_initoption='/data/pgsql/share/dict/german.stop'
db=> WHERE dict_name = 'de';
Der Pfad muß natürlich entsprechend angepaßt werden, je nachdem wo man die Stopdatei hingelegt hat. In dieser Datei stehen alle Wörter, die Tsearch2 ignorieren soll. Also wenn jemand nach die, der, das suchen will, ist das sicherlich nicht sehr sinnvoll. Damit wir nun eine funktionsfähige Tsearch2 Konfiguration bekommen, sind noch ein paar weitere SQL-Statements notwendig:
INSERT INTO pg_ts_cfg(ts_name, prs_name, locale) VALUES('default_german', 'default', 'de_DE.iso88591');
INSERT INTO pg_ts_dict
(SELECT 'de_ispell',
dict_init,
'DictFile="/data/pgsql/share/dict/german.med",'
'AffFile="/data/pgsql/share/dict/german.aff",'
'StopFile="/data/pgsql/share/dict/german.stop.ispell"',
dict_lexize
FROM pg_ts_dict
WHERE dict_name = 'de_ispell');
SELECT set_curdict('de_ispell');
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default_german', 'lhword', '{de_ispell,de}');
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default_german', 'lpart_hword', '{de_ispell,de}');
INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name) VALUES ('default_german', 'lword', '{de_ispell,de}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'word', '{de_ispell,de}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'url', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'host', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'sfloat', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'uri', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'int', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'float', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'email', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'hword', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'nlword', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'nlpart_hword', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'part_hword', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'nlhword', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'file', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'uint', '{simple}');
INSERT INTO pg_ts_cfgmap VALUES ('default_german', 'version', '{simple}');
Und damit wir unser neues Wörterbuch auch noch zum Default machen, setzen wir folgenden Befehl ab:
db=> UPDATE pg_ts_cfg SET locale='de_DE.iso88591' WHERE ts_name='default';
Wenn das durchgelaufen ist, kann man mal folgende Testquery absetzen:
db=> select to_tsvector('PostgreSQL ist weitgehend konform
mit dem SQL92/SQL99-Standard, d.h. alle in dem Standard geforderten
Funktionen stehen zur Verfügung und verhalten sich so, wie vom Standard
gefordert; dies ist bei manchen kommerziellen sowie nichtkommerziellen
SQL-Datenbanken bisweilen nicht gegeben.');
to_tsvector
* 'all':9 'bei':28 'd.h':8 'dem':6,11 'die':26 'ist':2,27 'mit':5
'sql':34 'und':18 'vom':23 'wie':22 'zur':16 'sich':20 'sowi':31
'nicht':37 'stehen':15 'gegeben':38 'konform':4 'manchen':29
'standard':12,24 'bisweilen':36 'gefordert':25 'verfügung':17
'verhalten':19 'funktionen':14 'postgresql':1 'weitgehend':3
'datenbanken':35 'geforderten':13 'kommerziellen':30
'sql-datenbanken':33 'nichtkommerziellen':32 'sql92/sql99-standard':7
(1 Zeile)*
Man sieht also hier jetzt, wie Tsearch2 den String zerlegt hat. Die Nummern dahinter sind die Positionen der Wörter im Text. So... Soweit wären wir nun also schon. Aber wir wollen natürlich nicht nur in einem Satz nach bestimmten Wörtern suchen, sondern in der Datenbank bzw. eben in verschiedenen Spalten. Nehmen wir als Beispiel eine Installation von der bekannten Forumsoftware phpBB. Dort gibt es eine Tabelle phpbb_posts_text (wenn man als Prefix bei der Installation phpbb belassen hat) die wiederum eine Spalte post_text hat. Diese Spalte ist vom Typ text. Da landen die Postings der User drin und da kann schon mal längerer Text werden. Und genau da drin wollen wir suchen können.
Zunächst fügen wir dieser Tabelle eine neue Spalte hinzu:
db==> ALTER TABLE phpbb_posts_text ADD COLUMN idxfti tsvector;
Anstatt wie bei "normalen" Indizies "hängt" dieser Index soz. an der Tabelle dran. Diese Spalte kann dann durch die Tsearch2 Operatoren und Funktionen und durch einen speziellen Index zur Volltextsuche genutzt werden. Diese Spalte heißt in diesem Fall idxfti. Es gibt einen Grundsatz, denn man einhalten sollte, wenn man einen Volltextindex erzeugt:
1. Tabelle befüllen
2. VACUUM FULL ANALYZE tablename;
3. Index erzeugen
4. VACUUM FULL ANALYZE tablename;
db==> UPDATE phpbb_posts_text SET idxfti=to_tsvector('default', post_text);
db==> VACUUM FULL ANALYZE phpbb_posts_text;
Der Funktion to_tsvector sagen wir hier, das wir die default Konfiguration verwenden wollen (die haben wir oben ja auf die deutschen Wörterbücher eingestellt) und das wir die Spalte post_text indizieren wollen. Möchte man mehrere Spalten indizieren, sieht das so aus:
db==> UPDATE phpbb_posts_text SET idxfti=to_tsvector('default',coalesce(post_text,'') ||' '|| coalesce(post_subject,''));
Nun erzeugen wir den eigentlichen Index:
db==> CREATE INDEX idxfti_idx ON phpbb_posts_text USING gist(idxfti);
Nun brauchen wir noch einen Trigger, der uns den Index auf den neuesten Stand hält, sobald ein neuer Eintrag hinzukommt:
db==> CREATE TRIGGER idxftiupdate BEFORE UPDATE OR INSERT ON phpbb_posts_text
db==> FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxfti, post_text);
Wenn man oben zwei Spalten für die Indizierung angegeben hat, sieht der Trigger etwas anders aus:
db==> CREATE TRIGGER idxftiupdate BEFORE UPDATE OR INSERT ON phpbb_posts_text
db==> FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxfti, post_text, post_subject);
Die Funktion tsearch2 akzeptiert mehrere Argumente, so das man hier die beiden Spalten nicht verknüpfen muss. Und dann war's dann auch schon... Jetzt kann man Abfragen starten bzw. man kann sich auch die Inhalte der Tabelle selber anschauen. Die neue Spalte enthält nämlich z.B. die gefundenen Wörter.
Samplequeries:
SELECT post_text FROM phpbb_posts_text WHERE idxfti @@ to_tsquery('default', 'haus & garten');
Links zum Thema:
Implementing Full Text Indexing with PostgreSQL
http://www.devx.com/opensource/Article/21674/0/page/3
Tsearch2 - Introduction
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/tsearch-V2-intro.html
Tsearch2 and Unicode/UTF-8 - German Unicode Datebase
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/tsearch2_german_utf8.html
Gendict - generate dictionary templates for contrib/tsearch2 module
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/README.gendict
Deutsche Ispell Stop-Datei
http://hannes.imos.net/german.stop.ispell
German stemming algorithm
http://www.snowball.tartarus.org/algorithms/german/stemmer.html
Deutsche Wörterbuch und Stop-Dateien
http://www.computec.de/dload/tsearch2_german_utf8.zip
Can't find tsearch config by locale
http://blog.gmane.org/gmane.comp.db.postgresql.openfts.general/month=20040801
USING TSEARCH AND POSTGRESQL FOR A WEB BASED SEARCH ENGINE
http://www.sai.msu.su/~megera/postgres/gist/tsearch/tsearch-intro.html
Tsearch V2 Notes
http://www.sai.msu.su/~megera/oddmuse/index.cgi/Tsearch_V2_Notes
Tsearch V2 Optimization
http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/docs/oscon_tsearch2/optimization.html
Tsearch V2 compound words
http://www.sai.msu.su/~megera/oddmuse/index.cgi/Tsearch_V2_compound_words
http://archives.postgresql.org/pgsql-general/2005-11/msg01113.php
Posted at 01:00vorm. Apr. 02, 2006 by cetixx in Tipps | Kommentare [7]
PERL: Wie installiert man schnell Pakete aus dem CPAN-Pool?
perl -MCPAN -e shell
starten. Wenn man dann z.B. das Apache::DBI Paket installieren will, gibt man auf dieser Shell dann einfach:
install Apache::DBI
ein.
Posted at 08:00nachm. März 16, 2006 by cetixx in Tipps | Kommentare [0]
Apache 2.2 und Tomcat mit mod_proxy_ajp verbinden
Seit dem Apache 2.2 gibt es ein neues Proxy-Modul names mod_proxy_ajp.
Damit kann man sich die ganze Konfigurationsorgie mit mod_jk/mod_jk2 z.T.
sparen, wenn man einen Apache vor einen Tomcat hängen möchte. Man hat ja dann alle Apache-Features zur Verfügung, so dass die workers.properties eigentlich nicht mehr gebraucht wird.
Die Sache ist im Prinzip relativ einfach. Zunächst kompiliert man einen Apache 2.2 z.B. so:
./configure
--prefix=/opt/apache/2.2 \
--enable-proxy \
--enable-proxy-ajp
--prefix => Wo soll der Apache installiert werden.
--enable-proxy => Das Grundgerüst soz. für den AJP-Proxy (ohne dieses Modul funkts nicht).
--enable-proxy-ajp => Das Apache-AJP-Kommunikationsmodul für den Tomcat
Wenn man den Apache mit
make
make install
fertig übersetzt und installiert hat, passt man die httpd.conf entsprechend seinen Bedürfnissen an. Dann muss man als nächstes noch die beiden Proxy-Module in der httpd.conf laden:
LoadModule proxy_module /opt/apache/2.2/modules/mod_proxy.so
LoadModule proxy_ajp_module /opt/apache/2.2/modules/mod_proxy_ajp.so
Und dann legt man noch fest, für welchen Kontext der Apache den Tomcat ansprechen soll. Wenn man also z.B. eine Tomcat Web-Applikation test.war im webapps-Verzeichnis hat, dann wird der Kontext hier wahrscheinlich /test sein. Also fügt man z.B. bei einem virt. Host (oder in der globalen Konfiguration) Folgendes hinzu:
<VirtualHost *:80>
ServerName blubberblah.com
ProxyRequests Off
ProxyPass /test ajp://127.0.0.1:8009/test
</VirtualHost>
Nach einem Apache Restart leitet der Apache nun also alles was mit http://blubberblah.com/test
beginnt zum Tomcat weiter, wo der Tomcat in diesem Fall auf Port 8009
auf AJP-Anfragen horcht. Ausserdem ist der Tomcat auf localhost
(127.0.0.1) gebunden, was immer eine ganz gute Idee ist, wenn man den
Port nicht für die ganze Welt öffnen möchte. Dafür hat man ja den
Apache eigentlich auch davor geschaltet...
Posted at 09:00nachm. März 14, 2006 by cetixx in Tipps | Kommentare [0]
IMAP: Mailboxen migrieren
Wenn man Mailboxen von einem IMAP-Server zu einem anderen migrieren möchte, dem hilft imapsync.
Posted at 08:00nachm. März 09, 2006 by cetixx in Tipps | Kommentare [0]