Andü: DISTINCT-änhliche Funktion

Hallo!

Gibt es in PHP eine Funktion, welche ähnlich der DISTINCT-Funktion von SQL, dopplete Einträge aus multidimensionale Arrays (hierbei funktioniert array_unique nicht) entfernt?

Im PHP-Handbuch gibt es für so etwas einen Tipp: http://www.php.net/manual/de/function.array-unique.php#36636
Bei diesem fehlt mir aber noch:

  • mehrere "Spalten" auf Gleichheit zu überprüfen (in SQL: GROUP BY)
  • ausgewählte "Spalten" zu summieren (addieren)
  • die zusammengefassten Einträge zählen

Im Moment bin ich an einer eigenen Umsetztung auf Basis des Tipps, aber die wird sehr komplex und somit langsam! Deshalb such ich etwas schnelleres...

Danke im Voraus...

  1. Moin!

    Im Moment bin ich an einer eigenen Umsetztung auf Basis des Tipps, aber die wird sehr komplex und somit langsam! Deshalb such ich etwas schnelleres...

    Hm. Ich nehme an, Du hast keine Datenbank, sonst würdest Du diese schon aus Performancegründen benutzen.

    Kommen die Daten aus (einer) (möglicherweise) großen Textdatei(en)? Auf einem UNIX/Linux-System? Wunderbar!

    Mein Tipp lautet:

    $daten=shellscript.sh;

    shellscript.sh ist hier eine zu schreibende Batchdatei in der Du allerhübschest und sehr performant sowie auf zauberhafte Art und Weise mit Tools wie (g)awk, grep, sed, tr, tail, head, cut *) und so weiter Deine Dateien solange durch pipes schicken kannst, bis die genau das gewünschte enthalten.

    *) Es gibt davon noch mehr, auch mit Funktionalitäten, wie join, sort etc.

    MFFG (Mit freundlich- friedfertigem Grinsen)

    fastix®

    --
    Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
    1. Hm. Ich nehme an, Du hast keine Datenbank, sonst würdest Du diese schon aus Performancegründen benutzen.

      Doch hab ich schon, aber ich will die log-Dateien, die der Server logged. Das heißt ich les alle log-Einträge ein und will dann die mit der selben IP und Datum zusammenfassen. Bei der Zusammenfassung möchte ich aber die geladenen Bytes summieren!
      Die Daten hab ich in einen Array eingelesen. Die Funktion kannst du dir hier ansehen: http://forum.de.selfhtml.org/?t=115336&m=738086

      $daten=shellscript.sh;

      shellscript.sh ist hier eine zu schreibende Batchdatei in der Du allerhübschest und sehr performant sowie auf zauberhafte Art und Weise mit Tools wie (g)awk, grep, sed, tr, tail, head, cut *) und so weiter Deine Dateien solange durch pipes schicken kannst, bis die genau das gewünschte enthalten.

      *) Es gibt davon noch mehr, auch mit Funktionalitäten, wie join, sort etc.

      Versteh ich nicht! Kannst du das mal auf meinen konkreten Fall beziehen?

      1. Moin!

        Doch hab ich schon, aber ich will die log-Dateien, die der Server logged. Das heißt ich les alle log-Einträge ein und will dann die mit der selben IP und Datum zusammenfassen. Bei der Zusammenfassung möchte ich aber die geladenen Bytes summieren!

        ...

        Versteh ich nicht! Kannst du das mal auf meinen konkreten Fall beziehen?

        Du kannst Tabellen in Textdateien spaltenweise ausgeben mit: cut
        Du kannst Textdateien zeilenweise und mit regex filtern mit: grep, egrep, fgrep
        Du kannst Textdateien sortieren mit: sort
        Du kannst Textdateien zeilenweise und spaltenweise bearbeiten mit: awk
        awk kann auch rechnen wie zum Bleistift summieren

        Hilfe liefert Dir man programmname oder info programmname und natürlich die Literatur wie "Linux/Unix in a nutshell"

        Oder besser noch das Linux Documentation Project

        MFFG (Mit freundlich- friedfertigem Grinsen)

        fastix®

        --
        Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
        1. Du kannst Tabellen in Textdateien spaltenweise ausgeben mit: cut
          Du kannst Textdateien zeilenweise und mit regex filtern mit: grep, egrep, fgrep
          Du kannst Textdateien sortieren mit: sort
          Du kannst Textdateien zeilenweise und spaltenweise bearbeiten mit: awk
          awk kann auch rechnen wie zum Bleistift summieren

          Na, das einlesen brauch ich nicht mehr, das hab ich schon hinbekommen! Jetzt will ich aber halt aus allen eingelesenen die gruppieren anhand der IP und des Datums und die Bytes sollen addiert werden...

          1. Moin!

            Na, das einlesen brauch ich nicht mehr, das hab ich schon hinbekommen! Jetzt will ich aber halt aus allen eingelesenen die gruppieren anhand der IP und des Datums und die Bytes sollen addiert werden...

            Dann versuch es doch mal mit den Funktionen wie

            explode(str), sämtlichen array-Funktionen, Scheifen (while, for, besonders foreach)....

            Die Hilfen hierzu liefert Dir php.net.

            MFFG (Mit freundlich- friedfertigem Grinsen)

            fastix®

            --
            Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
            1. Ich habe es hin bekommen! War bisschen Krampf, aber es geht!
              Hab sie so ausgelegt, dass man bei $group_keys und $sum_keys sowohl einzelne "Spalten" als auch mehrere (als Array) angeben kann!
              Wenn jmd. Verbesserungen und Optimierungen hat, bitte melden... Bin für alle Ideen offen! Fehlt vielleicht noch eine Funktion?
              Die ganze Funktion sollte ab PHP 4.1.0 laufen...

              function array_distinct ($array, $group_keys, $sum_keys = NULL, $count_key = NULL)
              {
               #Keys zu Arrays machen
               if (!is_array ($group_keys)) $group_keys = array ($group_keys);
               if (!is_array ($sum_keys)) $sum_keys = array ($sum_keys);
               #Variablen definieren
               $existing_sub_keys = array ();
               $output = array ();
               #Verarbeitung
               foreach ($array as $key => $sub_array){
                $puffer = NULL;
                #Keys gruppieren
                foreach ($group_keys as $group_key){
                 $puffer .= $sub_array[$group_key];
                }
                $puffer = serialize ($puffer);
                if (!in_array ($puffer, $existing_sub_keys))
                {
                 $existing_sub_keys[$key] = $puffer;
                 $output[$key] = $sub_array;
                }
                else{
                 $puffer = array_search ($puffer, $existing_sub_keys);
                 #Keys addieren
                 foreach ($sum_keys as $sum_key){
                  if (is_string ($sum_key)) $output[$puffer][$sum_key] += $sub_array[$sum_key];
                 }
                 #Keys zählen
                 if (!array_key_exists ($count_key, $output[$puffer])) $output[$puffer][$count_key] = 1;
                 if (is_string ($count_key)) $output[$puffer][$count_key]++;
                }
               }
               return $output;
              }

          2. Moin!

            Na, das einlesen brauch ich nicht mehr, das hab ich schon hinbekommen!

            Du bist Dir sicher, dass Du nicht die in der PHP.ini gesetzten Speichergrenzen knackst, wenn Du mal mehr als ein paar hundert Zugriffe hast? Die log-Dateien, die mein hoster mir zur Verfügung stellt sind oft deutlich über 20mB groß....

            fastix®

            --
            Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
            1. Du bist Dir sicher, dass Du nicht die in der PHP.ini gesetzten Speichergrenzen knackst, wenn Du mal mehr als ein paar hundert Zugriffe hast? Die log-Dateien, die mein hoster mir zur Verfügung stellt sind oft deutlich über 20mB groß....

              Also, bis jetzt nicht! 20MB ist aber auch ganz schön heftig. Die größten bei mir sind 30KB (entpackt ca. 300KB).
              Bei mir kommt noch hinzu, dass die Logs einzeln gepackt sind. Das heißt die müssen zur Laufzeit auch noch erst live entpackt werden. Ich hoff das Entpacken macht nicht viel aus...

              1. Moin!

                Du bist Dir sicher, dass Du nicht die in der PHP.ini gesetzten Speichergrenzen knackst, wenn Du mal mehr als ein paar hundert Zugriffe hast? Die log-Dateien, die mein hoster mir zur Verfügung stellt sind oft deutlich über 20mB groß....

                Also, bis jetzt nicht!

                Das zweite und dritte Wort stellt den Knackpunkt dar: Machst Du Deinen Webauftritt um auf ewig "so wenige" Besucher zu haben?

                Bei mir kommt noch hinzu, dass die Logs einzeln gepackt sind.

                gzip?

                $dummy=gzip -dc logs/access\_woche\_tag.gz > tmp/access\_woche\_tag;

                tmp\access_woche_tag ist Dein Baby. Du solltest es nach abarbeiten mit ulink("tmp/access_woche_tag") löschen. Ergänze ggf die Pfadangeben um das root-Verzeichnis Deines virtuellen hostes.

                MFFG (Mit freundlich- friedfertigem Grinsen)

                fastix®

                --
                Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
                1. Das zweite und dritte Wort stellt den Knackpunkt dar: Machst Du Deinen Webauftritt um auf ewig "so wenige" Besucher zu haben?

                  Wieviel Besucher hast du, dass du auf 20mb kommst? (grob überschlagen an die 2000 Zugriffe pro Tag)
                  Ich glaub zwar nicht, das meine Seite in nächster Zeit so groß wird, aber ich würde mich schon dafür interessieren es möglichst schnell abzuarbeiten. Wie kann man das schneller machen? Funktionieren tut es ja sehr konfortabel.

                  Bei mir kommt noch hinzu, dass die Logs einzeln gepackt sind.
                  gzip?

                  jo

                  $dummy=gzip -dc logs/access\_woche\_tag.gz > tmp/access\_woche\_tag;

                  tmp\access_woche_tag ist Dein Baby. Du solltest es nach abarbeiten mit ulink("tmp/access_woche_tag") löschen. Ergänze ggf die Pfadangeben um das root-Verzeichnis Deines virtuellen hostes.

                  Versteh ich nicht ganz! Soll das eine Funktion zum entpacken sein? Ich hab da gzgets genommen!

                  1. Hab grad festgestellt, dass die Dateien anscheinend doch zu groß sind!
                    Offline funzt das ohne Probleme, aber nicht auf dem "Online-Server"...
                    Was kann ich da tun?

                    1. Moin!

                      Hab grad festgestellt, dass die Dateien anscheinend doch zu groß sind!

                      Kann eigentlich nicht sein. Ein paar hundert Kilobyte sollten die Limits nicht sprengen, es sei denn Du kopierst die Daten ein paar Mal zwischen verschiedenen Variablen hin- und her.
                      Andererseits darfst Du bei gepackten Logfiles von 100kB durchaus annehmen, dass diese entpackt 1-2MB groß sind.

                      -> Lösche unbenötigte Variablen

                      Versuche ruhig mal die Daten so einzulesen:

                        
                      <?php  
                      $arZeilen=explode("\n", `gzip -dc logs/access_woche_tag.gz`);  
                      ?>  
                      
                      

                      Strings in backticks werden an die Shell übergeben und von dieser ausgeführt...

                      gzip -d -> deflate (entpacken)
                      gzip -c -> Normalerweise löscht gzip die (entpackte) Urdate und speichert die [ge-|ent-] packte Date [mit|ohne] der angehängten Endung .gz. Die Option -c sorgt dafür, dass die Datei nach stdout (normalerweise der Bildschirm, hier jedoch eine "Ausgabe") entpackt wird.

                      gzip -dc -> Die nachfolgende Datei wird also entpackt und an die Stelle "gekippt", wo das aufgerufen wird.

                      Du solltest danach in $arZeilen speichersparend Dein access.log haben.

                      Weiter:

                        
                      <?php  
                      echo `gzip -dc logs/access_woche_tag.gz | wc -c`; # Wieder in backticks  
                      ?>  
                      
                      

                      Liefert Dir die Größe der Datei zurück. Ganz ohne dass der Speicher von PHP in Anspruch genommen wird :)

                      MFFG (Mit freundlich- friedfertigem Grinsen)

                      fastix®

                      --
                      Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
                      1. Ich glaub das hilf alles nix! Ich hab mir mal versucht die ganzen Einträge in eine SQL-Datenbank zu ziehen...
                        Resultat: 7600 Einträge -> 800 kB (und das nur allein von Januar)
                        Da meine Datenbank auf 10MB beschränkt ist, lass ich das mal lieber...

                        Was bringt es mir, wenn ich die Dateien speichersparend einlesen kann, sie aber dann nicht speichersparend verarbeiten kann?
                        Irgendwie muss ich ja dann die Arrays, Strings oder was auch immer sortieren, gruppieren oder zählen!
                        Oder denkst du das größte Problem ist das Einlesen?

                        Gibt es da ein Skript/Programm in Perl oder PHP welches meine WebLogs auswerten kann? Ich hab eins, aber das läuft nur unter Windows!

                        PS: Ich weiß nicht genau, ob ich die Limits gesprengt hab - auf alle Fälle hat die Funktion einfach aufgehört (ohne Fehlermeldung) irgendetwas zu machen!

                        1. Moin!

                          auf alle Fälle hat die Funktion einfach aufgehört (ohne Fehlermeldung) irgendetwas zu machen!

                          Vieleicht gabs ja eine Warnung...

                          <?php
                          error_reporting(E_ALL);
                          ?>

                          Von einem Hoster mit 10MB Datenbank würde ich mich verabschieden. Das reicht ja für gar nichts... Ich vermute die Grenzen für Speicherverbrauch sind ähnlich restriktiv.

                          Die Menge der eingelesenen Daten beschneidest Du am effektivsten in dem Du mit cut oder awk ebendiese Dateien vorher von unnötigen Spalten befreist und mit greo ggf. die Anfragen der Robots von Suchmaschinen rausfilterst. ggf. hole Dir erst eine Liste der IPs und fann die Zugriffe von diesen

                          Tools zur Auswertung von der Logfiles des Apach gibt es wie Sand am Meer. z.B. Webalizer

                          Zudem wird einiges davon in selfhtml besprochen:
                          http://aktuell.de.selfhtml.org/artikel/server/self/logfiles.htm

                          MFFG (Mit freundlich- friedfertigem Grinsen)

                          fastix®

                          --
                          Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
                          1. Moin!

                            auf alle Fälle hat die Funktion einfach aufgehört (ohne Fehlermeldung) irgendetwas zu machen!
                            Vieleicht gabs ja eine Warnung...

                            Hatte ich eigentlich (glaub ich) aktiviert!

                            Von einem Hoster mit 10MB Datenbank würde ich mich verabschieden. Das reicht ja für gar nichts... Ich vermute die Grenzen für Speicherverbrauch sind ähnlich restriktiv.

                            Hab auch schon überlegt! Der Vertrag ist schon etwas älter! Hab insgesamt (mit Datenbank) 50MB - das reicht für meine Bedürfnisse. Ich bin aber noch dort, weil ich da eine Domain hab und E-Mail-Postfächer erstellen kann. Ich werd mich aber mal umschauen!

                            Die Menge der eingelesenen Daten beschneidest Du am effektivsten in dem Du mit cut oder awk ebendiese Dateien vorher von unnötigen Spalten befreist und mit greo ggf. die Anfragen der Robots von Suchmaschinen rausfilterst. ggf. hole Dir erst eine Liste der IPs und fann die Zugriffe von diesen

                            Kann ich jetzt nicht testen, bin grad auf Arbeit!

                            Tools zur Auswertung von der Logfiles des Apach gibt es wie Sand am Meer. z.B. Webalizer

                            Webalizer ist aber beispielsweise in C programmiert. Das bringt mir aber relativ wenig, weil ich nur PHP und PERL verwenden kann. Ich will aber immer die aktuellen Werte (am besten über Web-Interface) ausgewertet haben!

                            Zudem wird einiges davon in selfhtml besprochen:
                            http://aktuell.de.selfhtml.org/artikel/server/self/logfiles.htm

                            Mal schauen...

  2. echo $begrüßung;

    Gibt es in PHP eine Funktion, welche ähnlich der DISTINCT-Funktion von SQL, dopplete Einträge aus multidimensionale Arrays (hierbei funktioniert array_unique nicht) entfernt?

    Im PHP-Handbuch gibt es für so etwas einen Tipp: http://www.php.net/manual/de/function.array-unique.php#36636
    Bei diesem fehlt mir aber noch:

    • mehrere "Spalten" auf Gleichheit zu überprüfen (in SQL: GROUP BY)
    • ausgewählte "Spalten" zu summieren (addieren)
    • die zusammengefassten Einträge zählen

    Schau dir doch mal die restlichen Array-Funktionen an. Da gibt es beispielsweise noch:

    • array_filter --  Filters elements of an array using a callback function
    • array_map --  Applies the callback to the elements of the given arrays
    • array_reduce --  Iteratively reduce the array to a single value using a callback function
    • array_walk --  Apply a user function to every member of an array

    echo "$verabschiedung $name";

    1. Schau dir doch mal die restlichen Array-Funktionen an. Da gibt es beispielsweise noch:

      • array_filter --  Filters elements of an array using a callback function
      • array_map --  Applies the callback to the elements of the given arrays
      • array_reduce --  Iteratively reduce the array to a single value using a callback function
      • array_walk --  Apply a user function to every member of an array

      Diese Funktion sind doch aber auch nicht ursprünglich für multidimensionale Array ausgelegt!

      1. Moin!

        Diese Funktion sind doch aber auch nicht ursprünglich für multidimensionale Array ausgelegt!

        Dann behandele damit einfach genau die Dimension des Arrays, die Du zu behandeln wünschst...

        MFFG (Mit freundlich- friedfertigem Grinsen)

        fastix®

        --
        Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
      2. echo $begrüßung;

        Diese Funktion sind doch aber auch nicht ursprünglich für multidimensionale Array ausgelegt!

        Nein, das sind sie nicht unbedingt. Es kann nicht für jeden Sch.. - ich meine, für jedes spezielle Problem eine extra Funktion geben.

        Für das Behandeln tiefer verschachtelter Arrays ("multidimensional" ist bei PHP-Arrays meiner Meinung nach nicht die richtige Bezeichnung) gibt es Mechanismen wie die Rekursion.

        echo "$verabschiedung $name";