Выборка строк из большого списка

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Приветствую!
Есть список (файл) с большим количеством строк. Я этот список сортирую по ключевым словам.
Например:
поиск по списку слова "слон" - вырезаем строку из списка где есть слово "слон" и сохраняем вырезанную строку в файл слон.txt
.. и далее по циклу, пока не кончатся строки со словом "слон"..

Проблема с том, что исходный список (файл), по которому идет выборка, может составлять 100к и более строк... в итоге выборка идет очень медленно.. в файле может быть до 30% строк со словом "слон"... итого пока эти 30к строк по циклу найду, вырежу и вставлю в файл слон.txt проходит очень много времени..

Подскажите как можно ускорить выборку?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 238
Благодарностей
671
Баллы
113
Приветствую!
Есть список (файл) с большим количеством строк. Я этот список сортирую по ключевым словам.
Например:
поиск по списку слова "слон" - вырезаем строку из списка где есть слово "слон" и сохраняем вырезанную строку в файл слон.txt
.. и далее по циклу, пока не кончатся строки со словом "слон"..

Проблема с том, что исходный список (файл), по которому идет выборка, может составлять 100к и более строк... в итоге выборка идет очень медленно.. в файле может быть до 30% строк со словом "слон"... итого пока эти 30к строк по циклу найду, вырежу и вставлю в файл слон.txt проходит очень много времени..

Подскажите как можно ускорить выборку?
использовать for а не foreach, разбивать список на части и использовать parallel
 

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
использовать for а не foreach, разбивать список на части и использовать parallel
ничо не понял... очень сложно...
вот как пример в Notepad++ можно это сделать: найти строки со словом "слон" и пометить их - вырезать все строки с пометкой...
Итого всего 2 действия на поиск всех строк со словом "Слон"
Есть что то подобное в ZP?
 

Sherminator

Client
Регистрация
10.09.2021
Сообщения
1 238
Благодарностей
671
Баллы
113
ничо не понял... очень сложно...
вот как пример в Notepad++ можно это сделать: найти строки со словом "слон" и пометить их - вырезать все строки с пометкой...
Итого всего 2 действия на поиск всех строк со словом "Слон"
Есть что то подобное в ZP?
На шарпе точно есть, на кубиках не знаю
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 786
Благодарностей
2 450
Баллы
113
Создаем 3 списка:
Входящие данные
Есть слон
Нет слон
Привязываем их к файлам.

Первым действием берем строку с удалением с первого списка.
Вторым действием сравниваем есть ли там слон.
Третим действием сохраняем данные в список Есть слон или список Нет слон.
Завершаем работу шаблона.
Главное не добавлять уведомления, так как это может замедлить работу.
Запускаем в многопотоке (так сможем регулировать скорость количеством потоков) в Зеннопостере до 1 ошибки (ошибка будет когда закончатся данные в списке Входящие данные).

Выглядеть в коде это может быть примерно так:
C#:
var list_1 = project.Lists["input"];
var list_2 = project.Lists["good"];
var list_3 = project.Lists["bad"];

string pattern = "слон";
string line = string.Empty;
lock(SyncObjects.ListSyncer){
    line = list_1.GetItem("0", true); // Берем первую строку с удалением
}

if(line.Contains(pattern)){
    lock(SyncObjects.ListSyncer){
        list_2.Add(line); // Если есть
    }
}
else{
    lock(SyncObjects.ListSyncer){
        list_3.Add(line); // Если нет
    }
}
Если данная реализация не будет удовлетворять по скорости - то тогда пишите, будем думать как сделать быстрее.
 
Последнее редактирование:
  • Спасибо
Реакции: Tronheym

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Создаем 3 списка:
Входящие данные
Есть слон
Нет слон
Привязываем их к файлам.

Первым действием берем строку с удалением с первого списка.
Вторым действием сравниваем есть ли там слон.
Третим действием сохраняем данные в список Есть слон или список Нет слон.
Завершаем работу шаблона.
Главное не добавлять уведомления, так как это может замедлить работу.
Запускаем в многопотоке (так сможем регулировать скорость количеством потоков) в Зеннопостере до 1 ошибки (ошибка будет когда закончатся данные в списке Входящие данные).

Выглядеть в коде это может быть примерно так:
C#:
var list_1 = project.Lists["input"];
var list_2 = project.Lists["good"];
var list_3 = project.Lists["bad"];

string pattern = "слон";
string line = string.Empty;
lock(SyncObjects.ListSyncer){
    line = list_1.GetItem("0", true); // Берем первую строку с удалением
}

if(line.Contains(pattern)){
    lock(SyncObjects.ListSyncer){
        list_2.Add(line); // Если есть
    }
}
else{
    lock(SyncObjects.ListSyncer){
        list_3.Add(line); // Если нет
    }
}
Если данная реализация не будет удовлетворять по скорости - то тогда пишите, будем думать как сделать быстрее.
Спасибо. Счас затестю. Только вы усложнили задачу добавив третий список... у меня реализовано как: ищем строку с "слон" и вырезаем ее и вставляем в слон.txt - далее зацикливаем.... в итоге когда то кубик поиска выдаст ошибку (т.к. все строки со "слон" в исходном файле закончался. Это и есть завершение работы. В итоге имеем исходный файл без "слон" и файл слон.txt со строками где есть вхождение со словом "слон"..
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 786
Благодарностей
2 450
Баллы
113
Спасибо. Счас затестю. Только вы усложнили задачу добавив третий список... у меня реализовано как: ищем строку с "слон" и вырезаем ее и вставляем в слон.txt - далее зацикливаем.... в итоге когда то кубик поиска выдаст ошибку (т.к. все строки со "слон" в исходном файле закончался. Это и есть завершение работы. В итоге имеем исходный файл без "слон" и файл слон.txt со строками где есть вхождение со словом "слон"..
Я на задачу смотрю так - есть входные данные и есть результат.
Вашу задачу я привел именно к этому варианту, чтобы сделать сложность алгоритма линейным.

Вариант который будет делать поиск строки, после чего удалять строку в исходном списке будет работать дольше - так как список больше времени будет находиться в заблокированном состоянии (другой поток не сможет взять его в работу). Даже если работа будет выполняться на кубиках без кода - состояния синхронизации контекста в потоках не избежать, а значит время на поиск и удаление будет дольше чем просто взятие с удалением. Например в Вашем варианте если работа выполнена 50 000 раз - то последующие 50 000 раз мы будем делать проверки и в тех строках, где Вы уже удалили строки содержащие слово слон. А в моем варианте это поведение исключено.

Другими словами, в моем варианте мы делаем только 100 000 проверок, если в файле 100 000 строк.
В Вашем варианте Вы делаете 100 000 проверок * на (100 000 проверок - количество совпадений).
Если как заявлено 30% совпадений,тогда 100 000 * 66 000 = 6 600 000 000 проверок.
Понимаете в чем проблема?
Отсюда собственно и выходит длинное время выполенния.
 
Последнее редактирование:
  • Спасибо
Реакции: Tronheym

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Я на задачу смотрю так - есть входные данные и есть результат.
Вашу задачу я привел именно к этому варианту, чтобы сделать сложность алгоритма линейным.

Вариант который будет делать поиск строки, после чего удалять строку в исходном списке будет работать дольше - так как список больше времени будет находиться в заблокированном состоянии (другой поток не сможет взять его в работу). Даже если работа будет выполняться на кубиках без кода - состояния синхронизации контекста в потоках не избежать, а значит время на поиск и удаление будет дольше чем просто взятие с удалением. Например в Вашем варианте если работа выполнена 50 000 раз - то последующие 50 000 раз мы будем делать проверки и в тех строках, где Вы уже удалили строки содержащие слово слон. А в моем варианте это поведение исключено.
ну ок... просто у меня выборка идет не только по слову "слон", а и по другим словам... в этом случае удобно выдирать строки только из 1 исходного начального файла... поэтому ваш вариант с третьим списком немного не удобен...
К примеру как искать строки со вторым ключевым словом "слон 2"? Исходный первый список пустой...
нужно строки из списка bad переносить в первый список input..
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 786
Благодарностей
2 450
Баллы
113
ну ок... просто у меня выборка идет не только по слову "слон", а и по другим словам... в этом случае удобно выдирать строки только из 1 исходного начального файла... поэтому ваш вариант с третьим списком немного не удобен...
К примеру как искать строки со вторым ключевым словом "слон 2"? Исходный первый список пустой...
нужно строки из списка bad переносить в первый список input..
Сначала от Вас нужно два теста решения - в 1 поток и в 10 потоков, чтобы понять устраивает ли в целом скорость работы или нет.
Может оказаться, что в 1 поток скорости более чем достаточно.
После чего уже можно приступать к решению проблемы выборки по нескольким словам.

P.S. Можно ещё выполнять примерно так, используя Linq.
Перед этим кодом привязываем список good к файлу например слон 1.txt
При следующем выполнении кода - привязываем уже к слон_2.txt и тп.
Файл с входящим список строк будет перезаписан при каждом выполнении.
C#:
var input = project.Lists["input"].ToList();
var good = project.Lists["good"];
 
string pattern = "слон 1";

var temp_good = input.Where(x=>x.Contains(pattern));
var temp_bad = input.Where(x=>!x.Contains(pattern));

project.Lists["input"].Clear();
project.Lists["input"].AddRange(temp_bad.ToList());

good.AddRange(temp_good.ToList());
 
Последнее редактирование:
  • Спасибо
Реакции: Tronheym и Evgeny76

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Сначала от Вас нужно два теста решения - в 1 поток и в 10 потоков, чтобы понять устраивает ли в целом скорость работы или нет.
Может оказаться, что в 1 поток скорости более чем достаточно.
После чего уже можно приступать к решению проблемы выборки по нескольким словам.

P.S. Можно ещё выполнять примерно так, используя Linq.
Перед этим кодом привязываем список good к файлу например слон 1.txt
При следующем выполнении кода - привязываем уже к слон_2.txt и тп.
Файл с входящим список строк будет перезаписан при каждом выполнении.
C#:
var input = project.Lists["input"].ToList();
var good = project.Lists["good"];

string pattern = "слон 1";

var temp_good = input.Where(x=>x.Contains(pattern));
var temp_bad = input.Where(x=>!x.Contains(pattern));

project.Lists["input"].Clear();
project.Lists["input"].AddRange(temp_bad.ToList());

good.AddRange(temp_good.ToList());
вот это тема!
единственно не работает корректно, если вместо слон 1 в строке string pattern = "слон 1"; указать свою регулярку:
C#:
string pattern = "(?i).*{-Variable.key-}.*\\|";
не находит ничего, хотя в конструкторе рег выражений все отлично срабатывает...

п.с. Если вместо слон 1 указать ключ поиска/выборки - то все отлично работает..
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 786
Благодарностей
2 450
Баллы
113
вот это тема!
единственно не работает корректно, если вместо слон 1 в строке string pattern = "слон 1"; указать свою регулярку:
C#:
string pattern = "(?i).*{-Variable.key-}.*\\|";
не находит ничего, хотя в конструкторе рег выражений все отлично срабатывает...

п.с. Если вместо слон 1 указать ключ поиска/выборки - то все отлично работает..
Да, потому что задача была искать подстроку слон в строке списка,
Теперь Вы изменили задачу, и хотите искать по регулярному выражению.
В этом случае нужно заменить строки:

C#:
var temp_good = input.Where(x=>new Regex(pattern).IsMatch(x));
var temp_bad = input.Where(x=>!(new Regex(pattern).IsMatch(x)));
Кроме того формировать регулярку нужно примерно так, так как конструкция {-Variable.key-} предназначена для использования во всех кубиках кроме Свой C# код (может у новых версиях уже поменяли, я пользуюсь 5-й версией, не следил за новостями):

C#:
 string pattern = "(?i).*"+project.Variables["key"].Value+".*\\|";
Отпишитесь пожалуйста, работает как надо или нет.
Хорошего вечера.
 
  • Спасибо
Реакции: Tronheym и Alexmd

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Да, потому что задача была искать подстроку слон в строке списка,
Теперь Вы изменили задачу, и хотите искать по регулярному выражению.
В этом случае нужно заменить строки:

C#:
var temp_good = input.Where(x=>new Regex(pattern).IsMatch(x));
var temp_bad = input.Where(x=>!(new Regex(pattern).IsMatch(x)));
Кроме того формировать регулярку нужно примерно так, так как конструкция {-Variable.key-} предназначена для использования во всех кубиках кроме Свой C# код (может у новых версиях уже поменяли, я пользуюсь 5-й версией, не следил за новостями):

C#:
 string pattern = "(?i).*"+project.Variables["key"].Value+".*\\|";
Отпишитесь пожалуйста, работает как надо или нет.
Хорошего вечера.
Кубик C# зависает :-) висит в статусе выполнения бесконечно..
 

BAZAg

Client
Регистрация
08.11.2015
Сообщения
1 786
Благодарностей
2 450
Баллы
113
Кубик C# зависает :-) висит в статусе выполнения бесконечно..
Этот фрагмент кода я тестировал примерно с таким данными:
C#:
string pattern = @"\d+";
var input = new[]{"Первая", "Вторая 123456"," Третья 654987"};

var temp_good = input.Where(x=>new Regex(pattern).IsMatch(x));
var temp_bad = input.Where(x=>!(new Regex(pattern).IsMatch(x)));

return string.Join(Environment.NewLine, temp_good);
113348


В результате, я вижу что условия отрабатывают корректно.
Почему именно у Вас висит в статусе бесконечного выполнения - этого я не знаю...

Возможно создание объекта Regex нужно вынести с условия, чтобы он не создавался при обработке каждой строки, так как строк много, видимо это и провоцирует эту нагрузку:
C#:
var regex = new Regex(pattern);
var temp_good = input.Where(x=>regex.IsMatch(x));
var temp_bad = input.Where(x=>!(regex.IsMatch(x)));
 
  • Спасибо
Реакции: Tronheym и Alexmd

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
похоже какая то ерунда с моей регуляркой... в тестере регулярных выражений отлично работает, но в проекте кубик виснет...
а есть у меня старая регулярка на похожий проект - в тестере рег. выражений не находит совпадения, но в проекте работает... что за мистика..
 

Alexmd

Client
Регистрация
10.12.2018
Сообщения
1 022
Благодарностей
1 424
Баллы
113
Покажите реальные примеры своих данных, раз Вы не можете самостоятельно исправить каламбур, который тут развели со "слонами".
Идея в первом сообщении, регулярка показалась в середине темы, теперь и она не работает..
Список на 100К строк - это ничто
113350

C#:
//это необязательно
project.SendInfoToLog("заполняю тестовый список");
project.Lists["input"].Clear();
for(int i = 0; i < 100000; i++)
{
    var text = string.Concat(Enumerable.Repeat("sometext ", i % 10 + 1)) + $"| sometext {i}";
    var procent = Enumerable.Range(1, 10).Shuffle().First();
    if(procent <= 3) text = text.Insert(text.Length / procent, project.Variables["keyword"].Value);
    project.Lists["input"].Add(text);
}
//это все можно удалить
project.SendInfoToLog("начинаю сортировку");
var st = System.Diagnostics.Stopwatch.StartNew();


//----код
var key = project.Variables["keyword"].Value;//слово для поиска
var list = project.Lists["input"];//исходный список

var regexp = $"(?i).*{key}.*\\|";//составлю регулярку

var input = list.GetItems("all", true);//возьму все строки с удалением
var sorted = input.Where(x=>Regex.IsMatch(x, key));//отсортирую по ключу

File.WriteAllLines(Path.Combine(project.Directory, $"{key}.txt"), sorted);//запишу в файл отсортированный список
project.Lists["input"].AddRange(input.Except(sorted));//верну остальное в исходный список
//----код

project.SendInfoToLog($"исходный список: {input.Count()}\nстрок с ключом '{key}' {sorted.Count()}\nосталось в списке: {project.Lists["input"].Count}\nВремя отработки: {st.Elapsed}");
 
  • Спасибо
Реакции: Tronheym и BAZAg

Tronheym

Client
Регистрация
13.10.2016
Сообщения
146
Благодарностей
30
Баллы
28
Всем спасибо за помощь! Подредактировал свою регулярку и все заработало :-)
 
  • Спасибо
Реакции: Alexmd и BAZAg

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)