Come eseguire il data mining in modo efficiente (in PHP)?

3

Il momento di lavorare su un sistema che fornisce statistiche basate su alcuni dati raccolti dal database è arrivato nella mia azienda.

Come si raccolgono in modo efficiente le statistiche da un database in modo tale da non aggiungere troppi sovraccarichi nel caricamento di una pagina o troppa complessità nella gestione della cache?

Attualmente, le statistiche vengono calcolate in fase di esecuzione, nessun dato viene salvato o memorizzato nella cache, il problema è che quando aggiungi nuove statistiche, e anche quelle che vengono calcolate in fase di esecuzione, raggiungerò un punto in cui il sito web sta per essere realisticamente lento, il che non è accettabile.

L'unica idea che mi è venuta in mente per risolvere questo problema è la memorizzazione nella cache dei dati che hanno filtri di data oltre il giorno in cui sono calcolati.

Ad esempio, supponiamo che mi piacerebbe sapere se un utente ha visitato una pagina specifica tra il 2017-01-01 e il 2017-01-08. Da oggi è il 2017-01-12, è implicito che questo risultato non potrebbe mai cambiare in futuro, poiché le date selezionate sono vecchie.

Questo è un esempio di come calcolo le statistiche in Laravel (4.x):

namespace App\Composers\Users;

use Illuminate\Support\Collection;
use User;

class ShowComposer
{
    public function compose($view)
    {
        $viewData = $view->getData();

        $view->with([
            'sellings'    => $this->getSellingStatistics($viewData['user'])
        ]);
    }

    public function getSellingStatistics(User $user)
    {
        $sellings = [];

        $getSellingsOf = function (User $user, $months) {
            $startOfMonth = \Carbon::now()->subMonths($months)->startOfMonth();
            $endOfMonth   = \Carbon::now()->subMonths($months)->endOfMonth();

             return $user
                ->mavs()
                ->whereHas('buyerProposal', function ($proposal) use ($startOfMonth, $endOfMonth) {
                    $proposal->whereBetween('sold_at', [
                        $startOfMonth, $endOfMonth
                    ]);
                })
                ->count();
        };

        $sellings['best'] = value(function () use ($getSellingsOf) {
            $months = [];

            for ($month = 0; $month < 12; $month++) {
                $startOfMonth = \Carbon::now()->subMonths($month)->startOfMonth();
                $endOfMonth   = \Carbon::now()->subMonths($month)->endOfMonth();

                $query = <<<SQL
            SELECT
                id, (SELECT COUNT(*)
                    FROM 'mav'
                    INNER JOIN 'mav_proposals' ON 'mav'.'mav_proposal_id' = 'mav_proposals'.'id'
                    WHERE sold_at BETWEEN ? AND ?
                    AND mav.user_id = users.id) AS sellings
            FROM users
            ORDER BY sellings DESC
            LIMIT 1
SQL;

                $response = \DB::select($query, [
                    $startOfMonth->toDateTimeString(),
                    $endOfMonth->toDateTimeString()
                ]);

                $user = User::find($response[0]->id);

                $months[] = $getSellingsOf($user, $month);
            }

            $months = array_reverse($months);

            return $months;
        });

        $sellings['personal'] = value(function () use ($user, $getSellingsOf) {
            $months = [];

            for ($month = 0; $month < 12; $month++) {
                $months[] = $getSellingsOf($user, $month);
            }

            $months = array_reverse($months);

            return $months;
        });

        $sellings['global'] = value(function () use ($user) {
            $months = [];

            for ($month = 0; $month < 12; $month++) {
                $startOfMonth = \Carbon::now()->subMonths($month)->startOfMonth();
                $endOfMonth   = \Carbon::now()->subMonths($month)->endOfMonth();

                $companySoldMavs = \App\Models\MAV::whereHas('buyerProposal',
                    function ($proposal) use ($startOfMonth, $endOfMonth) {
                        $proposal->whereBetween('sold_at', [
                            $startOfMonth, $endOfMonth
                        ]);
                    })->count();

                $usersWithSoldMavs = \User::whereHas('mavs', function ($mav) use ($startOfMonth, $endOfMonth) {
                    $mav->whereHas('buyerProposal', function ($proposal) use ($startOfMonth, $endOfMonth) {
                        $proposal->whereBetween('sold_at', [
                            $startOfMonth, $endOfMonth
                        ]);
                    });
                })->count();

                $months[] = ($usersWithSoldMavs > 0)
                    ? round($companySoldMavs / $usersWithSoldMavs)
                    : 0;
            }

            $months = array_reverse($months);

            return $months;
        });

        return $sellings;
    }
}

Ora, ecco le uniche due opzioni a cui ho pensato:

  • Calcola le statistiche ogni 24 ore e salvale in un database.
  • Memorizza i dati sulla cache in base ai parametri utilizzati per raccogliere le statistiche.

La prima opzione è piuttosto complicata e richiede molto tempo per essere sviluppata in modo propizio.

La seconda opzione potrebbe essere interessante, tuttavia temo che la cache possa darmi mal di testa prima o poi.

C'è un altro modo per farlo in modo efficiente? In che modo le aziende si muovono verso il data mining? In questi casi le lingue come R vengono sempre utilizzate, oppure PHP può essere corretto se usato correttamente?

Per me è un nuovo mondo, per favore sii gentile.

    
posta GiamPy 12.01.2017 - 15:37
fonte

1 risposta

1

Ci sono due problemi in questo.

Prima di memorizzare i risultati (nel database o nella cache, ecc.) in modo che i calcoli non debbano essere rifatti ogni volta che viene caricata una pagina.

In secondo luogo è necessario un meccanismo per ripetere tutti i calcoli, si potrebbe aver trovato un difetto in un vecchio calcolo o vecchi dati vengono aggiornati / eliminati o nuovi calcoli vengono aggiunti.

Il modo migliore per farlo è aggiungere le tabelle nel database che contiene i calcoli in su e fino a un certo tempo (ad esempio ieri a mezzanotte). Quando vengono aggiunti nuovi calcoli, è necessario aggiornare tali tabelle o aggiungere nuove tabelle.

Ogni volta che è necessario, puoi svuotare le tabelle ed eseguire uno script che esegue i calcoli. Questo potrebbe benissimo essere uno script eseguito automaticamente ogni notte.

Ma dovrai anche essere in grado di cancellare le tabelle ed eseguire lo script manualmente.

Una nota importante è che le tabelle statistiche non dovrebbero contenere dati permanenti. I dati devono solo essere facilmente rigenerati.

L'idea che i vecchi dati non cambino mai è un'ipotesi pericolosa. È possibile avere origini dati che non sono più considerate affidabili. Ci possono essere molte ragioni per cui i vecchi dati diventano obsoleti. Progettare un sistema che faccia affidamento su vecchi dati che non cambiano mai sta progettando per il fallimento. Dovresti progettare per non dover fare affidamento sui vecchi dati.

    
risposta data 16.01.2017 - 13:07
fonte

Leggi altre domande sui tag