Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.08.15;
Скачать: [xml.tar.bz2];

Вниз

Нужен быстрый способ разбора строк   Найти похожие ветки 

 
Sens ©   (2004-08-02 11:01) [0]

Доброго Всем дня.

Возникла следующая проблема:
Есть лог файл  сквида (это одна строка)

1088655074.210   4710 192.168.1.249 TCP_MISS/200 406 GET http://www.internet-optimizer.com/conf/signin/? - DIRECT/65.39.191.5 text/html

Необходимо разобрать строку примерно по таким полям:

Время:  1088655074.210 <br>
Размер: 4710 <br>
Адрес запрашиваемого:  192.168.1.249 <br>
TCP_MISS/200 406 <br>
Метод (направление запроса): GET <br>
Адрес: http://www.internet-optimizer.com/conf/signin/? - DIRECT/65.39.191.5 text/html <br>

преобразовать это дело в базу (использую Access) для создания отчета по использованию интернет.

разделители между полями (в строке) пробелы, количество в разных строках разное (использовать какой либо формат для разбора не получается). На данный момент разбираю строку по алгоритму:
1. От позиции начала до первого пробела <br>
2. Запихиваю первое значение в базу (в нужное поле)<br>
3. Отсекаю все пробелы до первого не пробела <br>
4. Обрезаю строку.<br>
5. Повторяю цикл до конца строки.<br>
6. Повторяю цикл до конца файла.<br>

Все было хорошо пока файл был меньше 10МБ,на его преобразование уходило ~10-15 мин, но теперь он за месяц выростает до 60-100 МБ, и наш компик загибается на долгое время (2-4 часов).

Подскажите пожалуйста более быстрый алгоритм разбора строки (все упирается в него).


 
Sandman25 ©   (2004-08-02 11:07) [1]

Не надо ничего отсекать. Надо все время использовать Copy(S, StartIndex, ALength) и только правильно рассчитывать последние два параметра.
Тогда не будет лишних операций с исходной строкой.


 
sdw_syscoder   (2004-08-02 11:28) [2]

Sandman25 ©   (02.08.04 11:07) [1]

Дело не в этом, а в организации потоков.

А можно у Вас поинтересоваться как Вы организовали этот разбор строк, потому что у меня аналогичная проблема, но только с гораздо меньшим объёмом данных.

Моя ветка - http://delphimaster.net/view/1-1091395450/


 
Sens ©   (2004-08-02 11:32) [3]

Еще пример:
1067162459.277    261 192.168.1.5 TCP_MISS/200 363 GET http://...
1067162461.464   2322 192.168.1.5 TCP_MISS/200 7759 GET http:...

Второй параметр во второй строке отстоит от первого параметра уже на разное кол-во пробелов, использование copy избавит от необходимости "обрезания" но не избавит от необходимости считать пробелы.
Может подскажите какой-то способ более лучшего доступа к файлу или размещения его в памяти? Я обьявляю  TStringList и гружу в него файл.
Я в полной Ж. Моя прога за 1.5 часа только 40% разобрала... админ материться. ;)


 
Sandman25 ©   (2004-08-02 11:36) [4]

> Я обьявляю  TStringList и гружу в него файл.

О боже. Readln(S), где S - AnsiString. Все.


 
Sandman25 ©   (2004-08-02 11:36) [5]

[2] sdw_syscoder   (02.08.04 11:28)

Ничего не знаю. У автора про потоки ничего не сказано :)


 
default ©   (2004-08-02 11:37) [6]

Sens ©   (02.08.04 11:32) [3]
обрезать только ничего не надо...
посмотри можно-ли у тебя какое-то(ие-то) поле(я) сделать постоянного размера, только в этом случае разбор будет самым быстрым


 
panov ©   (2004-08-02 11:39) [7]

>Sens ©   (02.08.04 11:01)

В данном случае файл лучше(и намного) читать построчно(см. Sandman25 ©   (02.08.04 11:36) [4]), потому что на загрузку файла и обработку потребуется выделение большого количества памяти, что может привести еще и к свопингу...


 
Sens ©   (2004-08-02 11:46) [8]

to sdw_syscoder
У меня нет никаких потоков. Писал прогу давно и на C++ Builder, теперь хочу ускорить и написать на Delphi 7.

to Sandman25
/О боже. Readln(S), где S - AnsiString. Все./
Я бы заменил "О боже" на "леньтяй" или "ламер". :))
Попробую Readln(S). Спасибо.

А как считаете, если сначала пройтись по файлу и заменить "зоны пробелов" на один "Таб", а потом конвертнуть в Access текстовый файл скорость увеличится?


 
Sandman25 ©   (2004-08-02 11:49) [9]

>А как считаете

"Практика - критерий истины" :)


 
REA ©   (2004-08-02 11:51) [10]

1) Сдается мне, что это уже кто-то делал
2) Может использовать grep?


 
panov ©   (2004-08-02 11:51) [11]

У меня сделан разбор подобного лога(WinGate).
Я не оптимизировал особо, но на локальной БД ты не получишь приличного ускорения. У меня обработка файлов общим размером около 500Мб идет около часа, и немалое(если не основное время) занимает добавление записей в DBF...


 
Sens ©   (2004-08-02 12:03) [12]

to panov
А можно алгоритм разбора или кусочек кода?


 
Anatoly Podgoretsky ©   (2004-08-02 12:03) [13]

Насчет ReadLn может оказаться что разделители строк Юниксовские
Насчет загрузки в StringList рекомендую посмотреть выделеную память, думаю это охладит.
Лучше если это будет буферизированое чтение с разбором на строки или загрузка всего файла как единого целого в одну единственную строку и далее проход по пробелам, без какого либо деления, только копирование частей. При достаточном объеме оперативки и быстрых дисках это будет очень быстро. Если памяти мало, то буферизирование чтение и разбивка на строки.
Тогда 100 мб файл можно будет обработать за минуту/две максимум и остальное время уйдет на добавление в базу.


 
Рамиль ©   (2004-08-02 12:10) [14]

А в загрузке файла каждый раз полностью есть какой то глубинный смысл? Не лучше запоминать позицию и грузить только новые записи.


 
panov ©   (2004-08-02 12:11) [15]

Сразу говорю, что это не оптимизировано и реализовано неоптимально. это полусырой работающий вариант.
Функция обрабатывает 1 строку журнала WinGate(любого).


procedure TfWLogMain.ParseAndInsertLog(const Src: String;aFName: String);
 function QU(const src: String): String;
 begin
   Result := Src;
//    Result := """"+Src+"""";
 end;

var
 s,s1: String;
 pz: Integer;
 YY,MM,DD,HH,NN,SS: String;
 IP,Addr,Name,Sess: String;
 qType: String;
 qAddr: String;
 SentToClient,RecFromClient,SentForClient,RecForClient,sec: Integer;
 idDate,idFile,idType,idUser,idService: Integer;
begin
   s := Src;
   s := StringReplace(s,""","#",[rfReplaceAll]);
   s := StringReplace(s,"""","#",[rfReplaceAll]);
   MM := Copy(s,1,2);
   DD := Copy(s,4,2);
   YY := Copy(s,7,2);
   HH := Copy(s,10,2);
   NN := Copy(s,13,2);
   SS := Copy(s,16,2);
   Delete(s,1,18);

   pz := Pos(#9,s);
   if pz>0 then
   begin
     IP := Copy(s,1,pz-1);
     if not (IP[1] in ["0".."9"]) then Exit;
     Delete(s,1,pz);
   end
   else
   begin
     if Copy(s,1,28)="Service started successfully"
     then CurrWGSess := NewId("idSessWG");
     IP:="";
   end;

   pz := Pos(#9,s);
   if pz>0 then
   begin
     Name := Copy(s,1,pz-1);
     Delete(s,1,pz);
   end
   else Name:="";

   pz := Pos(#9,s);
   if pz>0 then
   begin
     Sess := Copy(s,1,pz-1);
     Delete(s,1,pz);
   end
   else Sess:="";

//    if sess="0001219699" then
//    begin
//      ShowMEssage("!");
//    end;

   pz := Pos(#9,s);
   if pz>0 then
   begin
     qType := Copy(s,1,pz-1);
     Delete(s,1,pz);
   end
   else
   begin
     if Copy(s,1,10)="Terminated"
       then qType:="Terminated"
       else
       begin
         if Copy(s,1,8)="Created:"
            then qType:="Created:"
            else
            if Copy(s,1,6)="Failed"
             then qType:="Failed"
             else qType := "";
       end
   end;

   if qType="Requested:" then
   begin
       Addr := Trim(s);
   end
   else Addr :="";

   if qType="Traffic" then
   begin
     pz := Pos(#9,s);
     if pz>0 then
     begin
       SentToClient := StrToInt(Copy(s,1,pz-1));
       Delete(s,1,pz);
     end
     else SentToClient:=0;

     pz := Pos(#9,s);
     if pz>0 then
     begin
       RecFromClient := StrToInt(Copy(s,1,pz-1));
       Delete(s,1,pz);
     end
     else RecFromClient:=0;

     pz := Pos(#9,s);
     if pz>0 then
     begin
       SentForClient := StrToInt(Copy(s,1,pz-1));
       Delete(s,1,pz);
     end
     else SentForClient:=0;

     pz := Pos(#9,s);
     if pz>0 then
     begin
       RecForClient := StrToInt(Copy(s,1,pz-1));
       Delete(s,1,pz);
     end
     else RecForClient:=0;

     sec := StrToInt(Copy(s,1,Length(s)-1));
     Delete(s,1,pz);

   end
   else
   begin
//      Exit;
     sec := 0;
     SentToClient:=0;
     RecFromClient:=0;
     SentForClient:=0;
     RecForClient:=0;
   end;

   if (qType="Requested:") or (qType="Traffic") then
   begin
     t.Append;
     idDate := CheckDate(YY+MM+DD);
     idUser := CheckUser(Name);
     idType := CheckType(qType);
     idService := CheckService(aFName);

//        Form1.t.FieldValues["dd"] := qu(DD);
//        Form1.t.FieldValues["mm"] := qu(MM);
//        Form1.t.FieldValues["yy"] := qu(YY);
       t.FieldValues["idSessWG"] := CurrWGSess;
       t.FieldValues["idDate"] := idDate;
       t.FieldValues["hhnnss"] := qu(HH+NN+SS);
//        Form1.t.FieldValues["nn"] := qu(NN);
//        Form1.t.FieldValues["ss"] := qu(SS);
       t.FieldValues["ip"] := qu(IP);
       t.FieldValues["idUser"] := idUser;
       t.FieldValues["idsess"] := Sess;
//        Form1.t.FieldValues["qType"] := qu(qType);
       t.FieldValues["idType"] := idType;
       t.FieldValues["idService"] := idService;
       t.FieldValues["Addr"] := qu(Addr);
       t.FieldValues["SentTo"] := SentToClient;
       t.FieldValues["RecFrom"] := RecFromClient;
       t.FieldValues["SentFor"] := SentForClient;
       t.FieldValues["RecFor"] := RecForClient;
       t.FieldValues["Sec"] := sec;
       t.Post;
   end;

end;


 
sdw_syscoder   (2004-08-02 12:27) [16]

Удалено модератором
Примечание: Личная переписка и офтопик


 
Sens ©   (2004-08-02 16:48) [17]

Написал, ускорение - УХ...

БЫЛО такое (Звеняйте за С++)

for (int j=0;j<fmMain->Memo1->Lines->Count-1;j++)
{
s=fmMain->Memo1->Lines->Strings[j];
int k=0;
sRes=s.SubString(0,s.Pos(".")-1);
CDate=DateTimeToStr(UnixToDateTime(StrToInt(sRes)+7200));
Record.Time=CDate;
int i=s.Pos(".");
s=s.SubString(i,s.Length());
//=============DateTime===============================
 i=0,k++;
DM->LogCommand->
   CommandText="INSERT INTO Log (RecTime,SendSize,UserIP,QueryType,ResiveSize,URL)";
DM->LogCommand->
   CommandText=DM->
   LogCommand->CommandText+"VALUES (:RecTime,:SendSize,:UserIP,";
DM->LogCommand->
   CommandText=DM->
   LogCommand->CommandText+":QueryType,:ResiveSize,:URL)";
   DM->LogCommand->Parameters->Items[0]->Value=Record.Time;
while (k!=8)
 {
  sRes=s.SubString(i,s.Pos(" ")-1);
  i=s.Pos(" ");
   while (s[i]==" ")
   {
    i++;
   }
  s=s.SubString(i,s.Length());
  i=0;
 switch (k)
      {
       case 1:  break;
       case 2: DM->LogCommand->Parameters->Items[1]->Value=StrToInt(sRes);  break;
       case 3: DM->LogCommand->Parameters->Items[2]->Value=sRes; break;
       case 4: DM->LogCommand->Parameters->Items[3]->Value=sRes; break;
       case 5: DM->LogCommand->Parameters->Items[4]->Value=StrToInt(sRes); break;
       case 6: break;
       case 7: DM->LogCommand->Parameters->Items[5]->Value=sRes.SubString(0,150); break;
      }
  k++;
}
DM->LogCommand->Execute();
fmMain->PB->Position=j;

СТАЛО ТАКОЕ!

procedure TfmMain.BitBtn1Click(Sender: TObject);
var
OD:TOpenDialog;
 F,ResF: TextFile;
 S,GET2,URL,URL2,IP,TempURL: string[200];
 CDate:TDateTime;
 i,PosMISS,PosGET,IPsp,URLpos1,URLpos2:integer;
begin
OD:=TOpenDialog.Create(Owner);
if OD.Execute then
Begin
   AssignFile(F, OD.FileName); { File selected in dialog }
   AssignFile(ResF,"111.txt");
   Rewrite(ResF);
   Reset(F);
   i:=1;
while not  Eof(F) do
begin
   Readln(F, S);
   PosMISS:=Pos("/",S)+4;
   PosGET:=Pos("GET",S)-1;
   if PosGET<1 then  PosGET:=Pos("POST",S)-1;
   URLpos1:=Pos("http://",S);
   URL:= Copy(S,URLpos1,50);
   TempURL:=Copy(S,URLpos1+7,50);
   URLpos2:=Pos("/",TempURL);
   URL:=Copy(URL,0,URLpos2+6);
   IP:=Copy(S,23,13);
   IPsp:=Pos(" ",IP);
   if IPsp>3 then IP:=Copy(IP,0,IPsp-1);
if  PosGET>1 then
 begin
   CDate:=UnixToDateTime(StrToInt(Copy(S,0,10))+7200);
   GET2:=Copy(S,PosMISS,PosGET-PosMISS);
   Writeln(ResF,DateTimeToStr(CDate)+";"+IntToStr(StrToInt(Copy(S,15,7)))+";"+IP+";"+IntToStr(StrToInt(GET2))+";"+URL);
   inc(i);
   Label1.Caption:=IntToStr(i);
   fmMain.Refresh;
   end;
end;
   CloseFile(F);
   CloseFile(ResF);
//====================================
OD.Free;
//====================================
End;
end;


Вывод:
Для разбора строк необходимо пользоваться функциями Pos и Copy, а не заниматься переприсваиванием строк!!!

Всем спасибо за участие.


 
Sens ©   (2004-08-03 10:02) [18]

to panov ©   (02.08.04 11:51) [11]
Нашел быстрый (ооочень быстрый) способ внесения данных в БД.
Не использую никаких компонент.
Готовлю файл (из файла описанного в сабже):
01.07.2004 6:11:14;192.168.1.249;http://...;5116
01.07.2004 6:11:16;192.168.1.249;http://...;1351

После чего делаю следующее:

 // Открываем Access
Label2.Caption:="Opening MS Access...";
fmMain.Refresh;
  Access := CreateOleObject("Access.Application");
  Access.Visible := False;
Label2.Caption:="Opening "+CurDir+"\log.mdb";
fmMain.Refresh;
  Access.OpenCurrentDatabase(CurDir+"\log.mdb", True);
  Access.DoCmd.DeleteObject (acTable, "Log");
  Label2.Caption:="Transfering to "+CurDir+"\log.mdb";
fmMain.Refresh;
  Access.DoCmd.TransferText (acImportDelim, "", "log",  CurDir+"\111.txt", False, "");
Label2.Caption:="Closeing "+CurDir+"\log.mdb";
fmMain.Refresh;
 Access.CloseCurrentDatabase;
 Access.Quit(acQuitSaveAll);

Label2.Caption:="Transfer complited succesfuly!!!";
 fmMain.Refresh;


Рекомендую использовать такой способ вместо вставки в DBF. Прирост в скорости гарантирован в десятки раз!!!

У меня на обработку лог файла 63Мб (530956 строк) и конвертирования его в Access на 2600+ Barton уходит 9 сек.
Если есть желание, могу слить конвертор (выложить некуда).


 
REA ©   (2004-08-03 10:49) [19]

>и немалое(если не основное время) занимает добавление записей в DBF...

используй прямой монопольный доступ к таблице через сторонние компоненты (например Degisy Data)


 
sniknik ©   (2004-08-03 11:02) [20]

можно попробовать перенести все запросом, правда переменное количество пробелов приводит в некоторое смущение ;о)).
зато если получится будет самый быстрый вариант.

слей часть лога на мой мыл, попробую вечером, если время будет. (без гарантий что рещу есно. и постарайся чтобы в часть попало все инвариантное (поближе к реальности ;о)))
да и сколько у тебя идет обработка? может и парится не стоит, а и так устраивает, как уже решил.


 
panov ©   (2004-08-03 12:16) [21]

>Sens ©   (03.08.04 10:02) [18]

Увы, Access я не использую... поэтому не смогу этим способом воспользоваться...



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.08.15;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.038 c
4-1089038837
juiceman
2004-07-05 18:47
2004.08.15
как с помощью WINAPI создать контекстное меню ?


3-1090466241
raptorus
2004-07-22 07:17
2004.08.15
Уважаемые мастера подскажите как можно просмотреть кодировку файл


14-1090964671
i-s-v
2004-07-28 01:44
2004.08.15
DirectX


1-1091096635
Прямой
2004-07-29 14:23
2004.08.15
OpenDialog


3-1090424668
GanibalLector
2004-07-21 19:44
2004.08.15
Возможно ли это ???





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский