ein Tupel "zufällig" auswählen, die Wahrscheinlichkeit wird über Attribut bestimmt

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • #16
    Mach dir mal ne Tabelle mit sovielen Testeinträgen, wie du maximal im Laufe der Zeit erwartest und ruf die mit PHP ab, ob das performancemäßig wirklich so schlimm ist. Vielleicht kommst du da eher zum Ziel.
    [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
    Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
    Super, danke!
    [/COLOR]

    Kommentar


    • #17
      Ich hoffe das Problem richtig verstanden zu haben ...
      PHP-Code:
      mysql_query('LOCK TABLES testsum READ');
      $res mysql_query('SELECT SUM(wk1) FROM testsum');
      $total mysql_result($res0);
      $res mysql_query('SELECT * FROM testsum ORDER BY RAND()*(wk1/'$total .') DESC LIMIT 1');
      $row mysql_fetch_object($res);
      mysql_query('UNLOCK TABLES'); 
      Zum Testen:
      PHP-Code:
      mysql_query('LOCK TABLES testsum READ');

      $res mysql_query('SELECT SUM(wk1) FROM testsum');
      $total mysql_result($res0);

      $count = array();
      for (
      $i 0$i 1000$i++) {
          
      $res mysql_query('SELECT id FROM testsum ORDER BY RAND()*(wk1/'$total .') DESC LIMIT 1');
          
      $row mysql_fetch_object($res);
          isset(
      $count[$row->id]) ? $count[$row->id]++ : $count[$row->id] = 1;
      }
      arsort($count);
      echo 
      '<pre>'.print_r($count,1).'</pre>';

      mysql_query('UNLOCK TABLES'); 
      Zuletzt geändert von onemorenerd; 22.08.2009, 12:36.

      Kommentar


      • #18
        Die Lösung passt offensichtlich nicht ganz, denn die ID 3 wird selbst bei 10000 Schleifendurchläufen nicht getroffen!? Die Wahrscheinlichkeiten passen also nicht.

        Kommentar


        • #19
          Naja die ID 3 hat halt wk1=3, was angesichts der anderen wk1-Werte zu einer sehr niedrigen Wahrscheinlichkeit führt. Dann gibt es bei der Division Rundungsfehler und RAND() ist auch nicht perfekt (Computer können Zufall nicht perfekt nachbilden). Ich denke das führt eben dazu, dass ID 3 bei 1000 Versuchen nicht auftritt.
          Hast du mal 100.000 oder noch mehr Versuche gemacht? Sollte selbst dann niemals ID 3 gezogen werden, müsste man sich mal RAND() im Zusammenspiel mit der Division genauer ansehen. Möglicherweise gibt es bei deinen Werten und der Ungenauigkeit von FLOAT überhaupt keine Chance für ID 3.

          Nachtrag: SELECT 3/252; liefert 0.0119. Da ist schon ein gehöriger Rundungsfehler drin, denn eigentlich ist es 1,190476190476e-02 oder noch mehr.
          Nachtrag2: Ich habe gerade 1.000.000 Versuche gemacht und auch dabei trat ID 3 nicht auf. Könnte zwar beim nächsten Anlauf anders sein, aber es erhärtet den Verdacht, dass so kleine Wahrscheinlichkeiten bei dieser Methode mit 0 zusammenfallen und diese Ereignisse dadurch niemals eintreten. Das ist dann aber kein Fehler sondern systembedingte Ungenauigkeit. Wenn das für dich nicht akzeptabel ist, musst du dir was anderes einfallen lassen. Entweder für andere wk1-Werte sorgen oder die Berechnung in einem Umfeld mit höherer Genauigkeit durchführen. Ein solches Umfeld wäre z.B. PHP mit bcmath.
          Zuletzt geändert von onemorenerd; 22.08.2009, 13:46.

          Kommentar


          • #20
            Zitat von onemorenerd Beitrag anzeigen
            Nachtrag: SELECT 3/252; liefert 0.0119. Da ist schon ein gehöriger Rundungsfehler drin, denn eigentlich ist es 1,190476190476e-02 oder noch mehr.
            Das ist kein Rundungsfehler. MySQL rechnet mit der Präzision der Argumente korrekt weiter. 3.0000/252.0000 liefert 0.01190476.

            @Boron: Du kannst in der Abfrage natürlich auch eine PHP-generierte Zufallszahl verwenden. Mit mt_rand() sollte dann schon was vernünftigeres rauskommen. Außerdem kennst du die Zufallszahl dann und kannst wirklich überprüfen, ob der korrekte Eintrag ausgewählt wurde. Außerdem kannst du die Grenzbereiche zwischen den summierten Gewichten (29.999--30.001, 79.999--80.001, u.s.w.) gezielt abtesten.
            Zuletzt geändert von AmicaNoctis; 22.08.2009, 13:56.
            [COLOR="DarkSlateGray"]Hast du die [COLOR="DarkSlateGray"]Grundlagen zur Fehlersuche[/color] gelesen? Hast du Code-Tags benutzt?
            Hast du als URL oder Domain-Beispiele example.com, example.net oder example.org benutzt?
            Super, danke!
            [/COLOR]

            Kommentar


            • #21
              Ok, und wenn ich dafür willkürlich einen Mindestwert vorgebe, sodass die Zeile überhaupt irgendwann mal getroffen wird?

              Sehe ich das richtig, dass das ORDER BY RAND()*(wk1/'. $total .') quasi für jeden Eintrag in der Tabelle vorgenommen wird? Das wäre bei vielen Datensätzen dann nicht mehr so prickelnd.

              Beim anderen Ansatz wird über alle Einträge aufsummiert und nur einmal eine Multiplikation mit einer Zufallszahl vorgenommen... den fand ich intuitiv besser.

              Du kannst in der Abfrage natürlich auch eine PHP-generierte Zufallszahl verwenden. Mit mt_rand() sollte dann schon was vernünftigeres rauskommen. Außerdem kennst du die Zufallszahl dann und kannst wirklich überprüfen, ob der korrekte Eintrag ausgewählt wurde.
              Danke, das ist es!

              PHP-Code:
              $durchlaeufe 3000;
              $result = array();
              mysql_query('LOCK TABLES testsum READ');
              $res mysql_query('SELECT SUM(wk1) FROM testsum');
              $total mysql_result($res0);
              for(
              $i=0$i<$durchlaeufe$i++) {
                  
              $zufallszahl mt_rand(0$total);
                  
              mysql_query("SET @a := 0");
                  
              $qry mysql_query("SELECT  `name` , ((@a := @a +  `wk1`) -  `wk1` ) AS  `summe` 
                                      FROM  `testsum`
                                      HAVING `summe` <= "
              .$zufallszahl."
                                      ORDER BY `summe` DESC
                                      LIMIT 1"
              ) OR DIE (mysql_error());
                  
              $row mysql_fetch_assoc($qry);    
                  isset(
              $result[$row['name']]) ? $result[$row['name']]++ : $result[$row['name']] = 1;
              }
              mysql_query('UNLOCK TABLES'); 
              Das liefert mir doch sinnvolle Ergebnisse:
              Code:
              Array
              (
                  [Heidi] => 788 (0.263%)
                  [Paul] => 569 (0.19%)
                  [Klaus] => 871 (0.29%)
                  [Caro] => 410 (0.137%)
                  [Peter] => 327 (0.109%)
                  [Simone] => 35 (0.012%)
              )
              So, hoffentlich hat sich nicht doch noch irgendwo ein Fehler eingeschlichen.

              Kommentar


              • #22
                Zitat von Boron Beitrag anzeigen
                Sehe ich das richtig, dass das ORDER BY RAND()*(wk1/'. $total .') quasi für jeden Eintrag in der Tabelle vorgenommen wird? Das wäre bei vielen Datensätzen dann nicht mehr so prickelnd.

                Beim anderen Ansatz wird über alle Einträge aufsummiert und nur einmal eine Multiplikation mit einer Zufallszahl vorgenommen... den fand ich intuitiv besser.
                Der eine Ansatz berechnet wk1/$total, der andere Ansatz berechnet @a - beide rechnen so oft wie es Datensätze gibt.

                Kommentar


                • #23
                  Ok, aber die Summenbildung verursacht wahrscheinlich weniger Aufwand als die RAND()-Funktion und die Multiplikation, oder?

                  Hätte die Tabelle 100 Datensätze, würde im Verfahren A) 100 Mal aufsummiert und einmal RAND() angewendet werden.
                  Im Verfahren B) würde 100 Mal RAND() angewendet werden. Richtig?

                  Kommentar


                  • #24
                    Das RAND() findet doch nun eh schon in PHP statt. Das ist auch richtig so. Jetzt bleibt bei genauer Betrachtung
                    A) 100 Additionen, 100 Subtraktionen, 100 Schreibzugriffe auf @a
                    B) 100 Divisionen

                    Keine Ahnung was schneller ist. Dürfte bei üblicher Tabellengröße auch kaum einen Unterschied ausmachen. Ich würde an deiner Stelle Variante B benutzen, weil sie einfacher zu verstehen ist. Du kanntest @-Variablen anfangs noch gar nicht, so geht es vielen ...

                    Kommentar

                    Lädt...
                    X