0

awstats ファイルをデータベースにインポートする作業を行っています。多数のファイルがあり、ファイルの最大サイズは約 10MB、大きなサイズのファイルでは約 200k 行です。ファイルはいくつかのセクションに分かれています。サンプルの 1 つを以下に示します。

BEGIN_GENERAL 8
LastLine 20150101000000 1379198 369425288 17319453580950
FirstTime 20141201000110
LastTime 20141231235951
LastUpdate 20150101000142 12317 0 12316 0 0
TotalVisits 146425              
TotalUnique 87968               
MonthHostsKnown 0                   
MonthHostsUnknown 103864              
END_GENERAL

これは小さなデータを含む小さなセクションです。数千行を含む非常に大きなセクションがあります。このプロジェクトでは Laravel と MYSQL を使用しており、セクションを JSON 形式でテーブルに保存しています。ファイルデータをデータベースに保存するコントローラーコードを次に示します。

<?php

namespace App\Http\Controllers;

use Validator;
use App\Models\Site;
use Illuminate\Http\Request;
use App\Helpers\AwstatsDataParser;
use App\Jobs\ProcessNewSiteStats;

class SiteController extends Controller
{
    private $dir_path;

    public function __construct(){
        $this->dir_path = config('settings.files_path');
    }
/**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string|',
            'domain' => 'required|regex:/(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/i|unique:sites,domain',
        ]);


        $site = Site::create([
            'title' => $request->title,
            'domain' => $request->domain,
            'status' => true,
        ]);
    
        ProcessNewSiteStats::dispatch($site);            
        return back()->with('success', 'Site is created Successfully');
    }
}

このコントローラーの機能は、サイトを保存し、当月ファイルのデータをデータベースにインポートするジョブを実行します。

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Models\Site;
use App\Models\Webstat;
use App\Helpers\AwstatsDataParser;

class ProcessNewSiteStats implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $site;
    private $dir_path;


    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Site $site)
    {
        $this->site = $site;
        $this->dir_path = config('settings.files_path');
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        if (is_dir($this->dir_path)) {
            $year = date('Y');
            $month = date('m');

            $fileName = "awstats{$month}{$year}.{$this->site->domain}.txt";

            $files_path = "{$this->dir_path}/$fileName";

            if (file_exists($files_path)) {

                $parser = new awstatsDataParser($files_path);
                $time = collect($parser->TIME);

                $webstat = Webstat::where('file_name', $fileName)->first();

                if(!$webstat){

                    $data = [
                        'file_name' => $fileName,
                        'month' => $month,
                        'year' => $year,
                        'total_visits' => $parser->GENERAL['TotalVisits'],
                        'total_unique' => $parser->GENERAL['TotalUnique'],
                        'total_hosts_known' => $parser->GENERAL['MonthHostsKnown'],
                        'total_hosts_unknown' => $parser->GENERAL['MonthHostsUnknown'],
                        'page_count' => $time->sum('Pages'),
                        'hit_count' => $time->sum('Hits'),
                        'bandwidth_count' => $time->sum('Bandwidth'),
                        'not_viewed_page_count' => $time->sum('NotViewedPages'),
                        'not_viewed_hit_count' => $time->sum('NotViewedHits'),
                        'not_viewed_bandwidth_count' => $time->sum('NotViewedBandwidth'),
                        'general' => $parser->GENERAL,
                        'time' => $parser->TIME,
                        'day' => $parser->DAY,
                        'login' => $parser->LOGIN,
                        'robot' => $parser->ROBOT,
                        'worms' => $parser->WORMS,
                        'email_sender' => $parser->EMAILSENDER,
                        'email_receiver' => $parser->EMAILRECEIVER,
                        'sider' => $parser->SIDER,
                        'domain' => $parser->DOMAIN,
                        'session' => $parser->SESSION,
                        'file_types' => $parser->FILETYPES,
                        'visitor' => $parser->VISITOR,
                        'downloads' => $parser->DOWNLOADS,
                        'os' => $parser->OS,
                        'browser' => $parser->BROWSER,
                        'screen_size' => $parser->SCREENSIZE,
                        'unknown_referer' => $parser->UNKNOWNREFERER,
                        'unknown_referer_browser' => $parser->UNKNOWNREFERERBROWSER,
                        'origin' => $parser->ORIGIN,
                        'se_referrals' => $parser->SEREFERRALS,
                        'page_refs' => $parser->PAGEREFS,
                        'search_words' => $parser->SEARCHWORDS,
                        'keywords' => $parser->KEYWORDS,
                        'misc' => $parser->MISC,
                        'errors' => $parser->ERRORS,
                        'cluster' => $parser->CLUSTER,
                        'sider_404' => $parser->SIDER_404,
                        'plugin_geoip_city_maxmind' => json_encode($parser->PLUGIN_geoip_city_maxmind, JSON_INVALID_UTF8_SUBSTITUTE),
                        'is_sync' => true,
                    ];


                    $webstats = $this->site->webstats()->create($data);

                }

            }

        }
    }
}

このコードは、小さなファイルの場合は問題なく実行されますが、大きなデータの場合はうまく実行されません。通常、MYSQL サーバーがなくなったというエラー、max_allocated_pa​​ckage タイプのエラーを受け取ります。

改善するために次のことを行いました。

  • データを分割して保存する (データを 3 つの部分に分割して必要なデータを保存し、残りのデータで行を更新するなど)
  • メモリサイズ、実行時間などを増やします。

しかし、私はそれらを保存する適切な方法を見つけています。これらに基づいて、1 つの要求で多くのファイルをインポートするスケジューラやその他のジョブを作成する必要があります。誰かがこの問題に関連する良いアイデアや提案を持っていれば、それは素晴らしいことです.

ありがとう

4

0 に答える 0