Andreas Korthaus: wo steht wordchar-Definition im MySQL-Quelltext?

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

  1. 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

    1. 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?

      1. 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)=='-')
        #endif

        Aber 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

        1. 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

          1. 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();

            strlen() ist nicht beliebig schnell, im Gegenteil :)

            $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

            1. 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 text

              verhindern. 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

              1. 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

                1. 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