wo steht wordchar-Definition im MySQL-Quelltext?
Andreas Korthaus
- datenbank
Hallo!
Ich habe jetzt ne ganze Zeit im MySQL Quelltext unter /myisam gesucht, vornehmlich in den Dateien die mit "ft_" anfangen, aber ich finde einfach nirgendwo eine Definition der "wordchar"-Funktion (die die Wort-Trennzeichen für den mySQL fulltext-index definieren soll), auch das Wort kommt so im gesamten Quelltext(und der mysql-Homepage und Google) nicht einmal vor, nur "word_char", aber da auch nicht direkt in dem Zusammenhang wie ich es mir vorstelle. Mag daran liegen das ich kein C kann, aber so einigermaßen kann ich das schon nachvollziehen, da es doch PHP oder eher PERL schon einigermaßen ähnelt. Ich habe auch keine Ahnung wonach genau ich suchen soll, da ich nicht wirklich weiß _wie_ das jetzt genau definiert wird. Kann mir vielleicht jemand sagen in welcher Datei des Quellcodes die Definition zu finden ist? Andere Dinge wie die stopword-Liste habe ich sofort gefunden (worin ich übrigens keine deutschen Wörter finde). Leider versteh ich den Quellcode aufgrund der Komplexität nicht gut geung um anhand dessen die Funktion/Definition zu finden.
Viele Grüße
Andreas
Hallo Andreas,
Ich habe jetzt ne ganze Zeit im MySQL Quelltext unter
/myisam gesucht, vornehmlich in den Dateien die mit "ft_"
anfangen, aber ich finde einfach nirgendwo eine Definition
der "wordchar"-Funktion
Die gibts nicht.
(die die Wort-Trennzeichen für den mySQL fulltext-index
definieren soll),
Das wird mit einem Makro gemacht:
ft_parser.c, Zeile 115:
#ifdef HYPHEN_IS_DELIM
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''')
#else
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''' || (X)=='-')
#endif
Dieses Makro ergibt 'true', wenn das Zeichen ein
Alphanumerisches Zeichen, _ oder ' ist. Wenn
'HYPHEN_IS_DELIM' nicht definiert ist, wird zusaetzlich
noch - mit in die Liste genommen.
Gruesse,
CK
Hallo Christian!
ft_parser.c, Zeile 115:
#ifdef HYPHEN_IS_DELIM
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''')
#else
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''' || (X)=='-')
#endif
Aber das ist doch auskommentiert, da muß es doch noch was anders geben, oder? Und ist diese Prüfung nicht etwas zu simpel um die Wörter für den Volltext-Index zu trennen? Das hieße ja Wörter nur durch durch '_', '' und Zahlen getrennt werden, oder? Es muß ja mindestens auch durch Leerzeichen getrennt werden, und Michael hat mir mal geschrieben, dass sogar '(' beim Suchen nicht beachtet würden, also dass auch bei diesen Zeichen getrennt werden müßte.
Das ft_parse.c habe ich mir nochmal angeguckt, und finde darin ehrlich gesagt keine Stelle, an der irgendeine Trennung bei Leerzeichen oder '(' durchgeführt werden könnte, aber wie gesagt ich verstehe den Quelltext nicht wirklich.
jedenfalls vielen Dank und viele Grüße
Andreas
PS: Wieso beschwert sich das Forum ich hätte "mehr als 50% zitierte Zeilen" in meinem Posting?
Hallo Andreas,
ft_parser.c, Zeile 115:
#ifdef HYPHEN_IS_DELIM
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''')
#else
#define word_char(X) (isalnum(X) || (X)=='_' || (X)==''' || (X)=='-')
#endifAber das ist doch auskommentiert,
Auskommentiert? *lol* Eine Raute (#) ist in C kein Kommentar.
Damit faengt eine Preprozessor-Direktive an. C ist eben doch
nicht PHP oder Perl ;)
da muß es doch noch was anders geben, oder?
Die komplette Parser-Arbeit findet in diesem Stueck Code
statt:
while (doc<end)
{
for (;doc<end;doc++)
if (word_char(*doc)) break;
for (w.pos=doc; doc<end; doc++)
if (!word_char(*doc)) break;
if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue;
if (w.len >= HA_FT_MAXLEN) continue;
if (is_stopword(w.pos, w.len)) continue;
if (!tree_insert(wtree, &w, 0))
{
delete_tree(wtree);
my_free((char*) wtree,MYF(0));
return NULL;
}
}
Wie du siehst, wird hier erst nach einem Wort-Anfang (erste
for-Schleife) gesucht, danach nach dem Wort-Ende (zweite
for-Schleife). Danach wird geprueft, ob die Wort-Laenge
kleiner als die minimale Wortlaenge ist. Schliesslich wird
geschaut, ob es ein Stopwort ist. Danach wird das Wort in
den Baum eingefuegt.
Und ist diese Prüfung nicht etwas zu simpel um die Wörter
für den Volltext-Index zu trennen?
Nein, warum?
Das hieße ja Wörter nur durch durch '_', '' und Zahlen
getrennt werden, oder?
Nee, ganz und gar nicht. Das heisst, Woerter werden durch
*alle* Zeichen ausser a-zA-Z0-9_' und optional noch -
getrennt.
Es muß ja mindestens auch durch Leerzeichen getrennt
werden,
Leerzeichen ist nicht in a-zA-Z0-9_' enthalten.
und Michael hat mir mal geschrieben, dass sogar '(' beim
Suchen nicht beachtet würden, also dass auch bei diesen
Zeichen getrennt werden müßte.
Auch ( und ) sind nicht in der Zeichenmenge enthalten.
PS: Wieso beschwert sich das Forum ich hätte "mehr als 50%
zitierte Zeilen" in meinem Posting?
Weil du nur 2 oder 3 Zeilen im Vergleich zu 7 geschrieben
hast? :)
Gruesse,
CK
Hi Christian!
Wie du siehst,
am besten "wie man leicht sieht..." ;-)
Das hieße ja Wörter nur durch durch '_', '' und Zahlen
getrennt werden, oder?Nee, ganz und gar nicht. Das heisst, Woerter werden durch
*alle* Zeichen ausser a-zA-Z0-9_' und optional noch -
getrennt.
So grob habe ich es verstanden, hatte das genau anders herum gedacht, aber so rum ist es auch erheblich einfacher!
Wenn ich jetzt selbst eien Funktion schreibe, die aus einem textstring die Worte trennt, wie mache ich das am besten(möglichst performant) in PHP?
Ich hatte mir das jetzt mal so überlegt:
for ($i=0,$word_start=0;$i<strlen($input_string);$i++) {
if(preg_match("/[^a-zA-Z0-9äöüÄÖÜ_/-]/",substr($input_string,$i,1))) {
if($word_end) {
$word_array[] = substr($input_string,$word_start);
}
$word_start = $i+1;
unset($word_end);
}
else {
$word_end = $i;
}
}
Was sagst Du dazu? Da ich ja ne ganze Menge Text parsen muß, ist ein regulärer Ausdruck vermutlich fehl am Platz, oder? Auch meine if-Konstruktion erscheint mir nicht wirklich optimal zu sein, oder? Aber wie soll man das sonst lösen? Und auch die Verwendung von substr(), leider kenne ich keine andere Methode einen String buchstabenweise zu durchsuchen.
PS: Wieso beschwert sich das Forum ich hätte "mehr als 50%
zitierte Zeilen" in meinem Posting?Weil du nur 2 oder 3 Zeilen im Vergleich zu 7 geschrieben
hast? :)
Das ist aber blöd, nicht jeder fügt manuell Zeilenumrüche in laufenden Text ein, oder? Zumindest hatte ich deutlich mehr geschrieben als zitiert.(und mehr Zeilen auf dem Bildschirm hatte ich auch ;-))
Nochmals vielen Dank!
Grüße
Andreas
Hallo Andreas,
So grob habe ich es verstanden, hatte das genau anders
herum gedacht, aber so rum ist es auch erheblich einfacher!
Vor allem sinnvoller *g*
for ($i=0,$word_start=0;$i<strlen($input_string);$i++) {
if(preg_match("/[^a-zA-Z0-9äöüÄÖÜ_/-]/",substr($input_string,$i,1))) {
if($word_end) {
$word_array[] = substr($input_string,$word_start);
}
$word_start = $i+1;
unset($word_end);
}
else {
$word_end = $i;
}
}Was sagst Du dazu?
Da ist ein Fehler drin. Und der RegEx ist auch unnoetig. Ich
wuerde an deiner Stelle es etwa so machen:
define('MIN_WORD_LEN',2);
$Stopwords = Array(
'wort1' => 1,
'wort2' => 1
);
function is_wchar($c) {
if(ord($c) >= 48 && ord($c) <= 122) return true;
switch($c) {
case 'ä':
case 'Ä':
case 'ö':
case 'Ö':
case 'ü':
case 'Ü':
case 'ß':
case '_':
case '/':
case '-':
return true;
}
return false;
}
$words = Array();
$len = strlen($input);
while($pos<$len) {
# lets find the beginning of the next word
for($begin=$pos;!is_wchar($input{$begin});++$begin);
# lets find the end of the next word
for($end=$begin;is_wchar($input{$end});++$end);
$pos = $end + 1;
$wrd = substr($input,$begin,$len-$end);
if($end-$begin < MIN_WORD_LEN) continue;
if($Stopwords[strtolower($wrd)]) continue;
$words[] = $wrd;
}
Aber wie soll man das sonst lösen?
Na, genau so, wie es in C geschrieben wird? :)
Und auch die Verwendung
von substr(), leider kenne ich keine andere Methode einen
String buchstabenweise zu durchsuchen.
Da hilft das Manual ab.
Das ist aber blöd, nicht jeder fügt manuell Zeilenumrüche
in laufenden Text ein, oder?
Nein. Aber es ist Absicht. Ich moechte Postings wie
q text text
q text text
blahr
q text text
q text text
verhindern. Also so Postings, die einfach mitten drin was
schreiben, ohne ueberfluessige Quotes zu loeschen.
Gruesse,
CK
Hallo Christian!
Vor allem sinnvoller *g*
... hast ja Recht ;-)
Was sagst Du dazu?
Da ist ein Fehler drin. Und der RegEx ist auch unnoetig.
:-(
Ich wuerde an deiner Stelle es etwa so machen:
:-)
define('MIN_WORD_LEN',2);
$Stopwords = Array(
'wort1' => 1,
'wort2' => 1
);
wieso weist Du den Elementen denselben Wert zu? könnte man nicht einfach statt
if($Stopwords[strtolower($wrd)]) continue;
$Stopwords = Array(
'wort1',
'wort2'
);
[...]
if(in_array($Stopwords)) continue;
schreiben? Oder ist das nicht so gut?
function is_wchar($c) {
if(ord($c) >= 48 && ord($c) <= 122) return true;switch($c) {
case 'ä':
case 'Ä':
case 'ö':
case 'Ö':
case 'ü':
case 'Ü':
case 'ß':
case '_':
case '/':
case '-':
return true;
}return false;
}
das verstehe ich noch... ich hätte das vermutlich mit einem Array mir den gültigen Zeichen und if(in_array()) gemacht, aber diese Variante dürfte besser sein, da die Zeichen nicht alle durchprobiert werden müssen.
$words = Array();
strlen() ist nicht beliebig schnell, im Gegenteil :)
$len = strlen($input);
while($pos<$len) {
das auch noch...
# lets find the beginning of the next word
for($begin=$pos;!is_wchar($input{$begin});++$begin);
das nicht mehr. Vor alllem kenne ich nicht die syntax $input{$begin}, was ist das? $input ist doch ein String, vermutlich definierst Du ein Zeichen des Strings, aber wo steht das im Manual?
Na, genau so, wie es in C geschrieben wird? :)
Das konnte ich in PHP nicht nachbilden, aber es scheint ja doch zu gehen ;-)
Und auch die Verwendung
von substr(), leider kenne ich keine andere Methode einen
String buchstabenweise zu durchsuchen.Da hilft das Manual ab.
vermutlich, aber wo? Ich habe gestern nochmal jede einzelen String-Funktion angeguckt, heute nochmal, und nochmal alle Array-Funktionen, ich könnte das nicht anders als wie beschrieben mit substr(). Wo steht da was im Manual?
Nein. Aber es ist Absicht. Ich moechte Postings wie
q text text
q text text
blahr
q text text
q text textverhindern. Also so Postings, die einfach mitten drin was
schreiben, ohne ueberfluessige Quotes zu loeschen.
Verstehe ich, aber wird das denn irgendwann zur Pflicht? Dann könnte ich manchmal nicht das schreiben/zitieren was ich wollte, auf der anderen Seite bringt die Ermahnung alleine vermutlich eh nichts :-(
Danke nochmal! Hast mir sehr geholfen, auch wenn ich es noch nicht zu 100% nachvollziehen kann ;-)
Viele Grüße
andreas
Hallo Andreas,
define('MIN_WORD_LEN',2);
$Stopwords = Array(
'wort1' => 1,
'wort2' => 1
);wieso weist Du den Elementen denselben Wert zu?
Weil ich nur einen true value brauche.
könnte man nicht einfach statt
if($Stopwords[strtolower($wrd)]) continue;
$Stopwords = Array(
'wort1',
'wort2'
);
[...]
if(in_array($Stopwords)) continue;schreiben?
Wenn man bei jedem Lookup eine Suche starten will, kann man
das schon tun, ja.
Oder ist das nicht so gut?
Hash-Lookups sind wesentlich schneller als eine Suche, die
in diesem Fall nichtmal binaer sein kann. Ein Hash-Lookup
braucht nur die Berechnung einer Hash-Summe und dann das
Nachschauen in einer Tabelle. Eine gute Hash-Funktion braucht
nur 6xKeylaenge + 32 Zyklen, um die Hash-Summe auszurechnen.
Eine Suche muss fast immer langsamer sein.
# lets find the beginning of the next word
for($begin=$pos;!is_wchar($input{$begin});++$begin);
das nicht mehr.
Nun, ich gehe in dem String solange vorwaerts, wie ich
Zeichen kriege, die *kein* Wort-Zeichen sind.
Vor alllem kenne ich nicht die syntax
$input{$begin}, was ist das? $input ist doch ein String,
vermutlich definierst Du ein Zeichen des Strings, aber wo
steht das im Manual?
Hier:
http://www.php.net/manual/de/language.types.string.php
Verstehe ich, aber wird das denn irgendwann zur Pflicht?
Was meinst du?
Dann könnte ich manchmal nicht das schreiben/zitieren was
ich wollte,
Doch -- mach halt Zeilenumbrueche rein.
Gruesse,
CK
Hallo!
Hash-Lookups sind wesentlich schneller als eine Suche, die
in diesem Fall nichtmal binaer sein kann. Ein Hash-Lookup
braucht nur die Berechnung einer Hash-Summe und dann das
Nachschauen in einer Tabelle. Eine gute Hash-Funktion braucht
nur 6xKeylaenge + 32 Zyklen, um die Hash-Summe auszurechnen.
Eine Suche muss fast immer langsamer sein.
Die Vorgehensweise sollte ich mir wohl mal merken!
Hier:
http://www.php.net/manual/de/language.types.string.php
da hatte ich schon geguckt, war aber _sehr_ unauffällig platziert ;-)
Verstehe ich, aber wird das denn irgendwann zur Pflicht?
Was meinst du?
Ich meine ob es irgendwann unmöglich wird zu posten wenn man mehr als 50% zitiert?
Doch -- mach halt Zeilenumbrueche rein.
ok,ok ;-)
Danke nochmal!
Grüße
Andreas