Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.08.27;
Скачать: CL | DM;

Вниз

Увеличить скорость выполнения   Найти похожие ветки 

 
User   (2010-04-06 22:02) [0]

Здравствуйте. Очень нужен совет опытных людей.
У меня имеется список строковых предложений (По 4-5 слов в среднем) загруженных в TStringList. Количество предложений около 50 тыс.

Пример предложений:
0. Товарищество с ограниченной ответственностью
1. Открытое Акционерное Общество
2. закрытое Акционерное Общество
и т.п.

При вводе пользователем определенного текста, например  "Акционерное общество", система ищет данный текст по нашему списку, и сравнивает с помощью "специальной функции сравнения 2х текстов" на процент схожести. Если процент переваливает за (например 70%) текст из списка должен быть отображен.

Проблема в том, что поиск происходит очень долго, при явном сравнении  текстов типа (Str = SL.String[i]) Поиск на много быстрее, но функция сравнения на процент схожести, единственная самая быстрая которую я нашел. Подскажите, как можно ускорить процесс поиска, может быть использование потоков?  Если да, то если можно по подробнее. Спасибо.

Сама функция нечеткого сравнения, взято из http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1147

function CompareStrings(S1, S2: string; MatchCount: integer;
                       out NCount: integer):integer;
var i, j, Count_, Count: integer;
   S1_, S2_: String;

 function Flag:Boolean;
 begin
   Result:= false;
   if (i + Count_ <= Length(S1_))and(j + Count_ <= Length(S2_)) then
     if (UpCharRus(S1_[i+Count_]) = UpCharRus(S2_[j+Count_]))
     {and(S1[j+Count_] <> " ")} then
       Result:= true;
 end;

begin
 Count:= 0;
 NCount:= 0;

 S1_:=S1;
 ReplaceAllStr(S1_, " ", "");
 S2_:=S2;
 ReplaceAllStr(S2_, " ", "");
 if (S1_ = "")or(S2_ = "") then
     begin
       Result:= 0;
       NCount:= 255;
       Exit;
     end;
 i:= 1;
 repeat
   j:= 1;
   repeat
     if (UpCharRus(S1_[i]) = UpCharRus(S2_[j])){and(S1[i] <> " ")} then
       begin
         Count_:= 1;
         while flag do
           Inc(Count_);
         i:= i + Count_ - 1;
         j:= j + Count_ - 1;
         if Count_ >= MatchCount then
         Count:= Count + Count_;
       end;
     inc(j)
   until j >= Length(S2_);
   inc(i)
 until i >= Length(S1_);

 if Length(S1_) < Length(S2_) then
   Count_:= Length(S1_)
 else
   Count_:= Length(S2_);
Result:= Count;
NCount:= Count_ - Count;
end;


 
User   (2010-04-06 22:05) [1]

Забыл добавить, поиск по вхождению исключается, поиск должен быть именно "нечеткого сравнения"


 
Харакири   (2010-04-06 22:28) [2]

>Забыл добавить, поиск по вхождению исключается, поиск должен быть именно "нечеткого сравнения"

Смотрю, у тебя не только сравнение "нечеткое", но и все остальное - такое же нечеткое. Особенно постановка вопросов.
Тебе что надо-то: "нечеткое сравнение" или "увеличить скорость выполнения"?

>UpCharRus(), ReplaceAllStr

Что это такое? Что-то это не то. Совсем не то. Приведи код.

>Количество предложений около 50 тыс.

Как ты перебираешь список? Не хочешь ли ты сказать, что у тебя до 50 000 * 50 000 = 2 500 000 000 сравнений?

Вообще, хорошо бы для каждой строки один раз высчитать свой некий хеш, наподобие SoundEx, и сравнивать хеши.


 
Jeer ©   (2010-04-06 22:35) [3]


> User   (06.04.10 22:02)  


Т.е пройти курс [само]обучения по известным талмудам для тебя не хляет ?


 
Дмитрий Белькевич   (2010-04-06 22:50) [4]


> Как ты перебираешь список? Не хочешь ли ты сказать, что
> у тебя до 50 000 * 50 000 = 2 500 000 000 сравнений?


Ну почему же - юзер ввёл строку, сравнили с 50-ю тысячами образцов.

1. Перевести код в асм. Может дать некоторое ускорение.
2. Попробовать распараллелить на 5-10 потоков. Все сравниваемые строки предварительно делятся на 5-10 TStringList"ов, каждый TStringList считается своим потоком.
3. Идеальный вариант - это использовать не саму строку, но её "слепок" - хэш, либо какую-то свою функцию - резать строку как-то на буквы/слоги/слова, считать их количество, или еще как-то. Идея в том, что бы сравнивать не "сырые данные" - строки, а предварительно так подготовленные, что бы можно было сравнивать "слепки" строк обычным сравнением, что даст наибыстрейшее нечёткое сравнение.

С этим алгоритмом, думаю, существенного прироста добиться не удастся. Неалгоритмическое ускорение, если повезёт, даст ускорение на порядок, думаю, не больше.


 
Jeer ©   (2010-04-06 23:17) [5]


> Неалгоритмическое ускорение, если повезёт, даст ускорение
> на порядок, думаю, не больше.


Типа, пошел к цыганке, она нагадала, ты скинул ей и все путем ?
***
Бляха-муха - я просто валяюсь в песке под пирамидами от таких вот "советчиков".


 
Дмитрий Белькевич   (2010-04-07 00:19) [6]


> Типа, пошел к цыганке, она нагадала, ты скинул ей и все
> путем ?


Типа как-то так, да.


 
Дмитрий Белькевич   (2010-04-07 00:32) [7]

Предлагайте, Jeer, свой метод.

И так... Морщины сокращаются на 34.56%...


 
MsGuns ©   (2010-04-07 00:32) [8]

Самое правильное решение - положить все эти "стотыщпяцот" названий на какой-нибудь склсервер и привести его в порядок (по крайней мере избавиться от перестановок одинаковых слов и "разнокапитанистых" букав) - на "доске" сразу прояснится, гад буду :)


 
MsGuns ©   (2010-04-07 00:38) [9]

Эх, а вот интересно, у меня есть программулька, которая в указанной таблице сканирует столбец (CHAR) и определяет те поля, в которых не все  символы в русской, украинской или английской кодировке, т.е. смешанный.
Сравнение идет посимвольное.
Так вот , даже на миллионных таблицах  время сканирования одного столбца не превышает нескольких минут.


 
Игорь Шевченко ©   (2010-04-07 00:46) [10]

Я только не совсем понял, требуется четкое совпадение или нечеткое ?
Если четкое, то хэш-таблица однозначный выбор при неплохой хэш-функции, если нечеткое, то сравнивать можно
а) в одном регистре
б) без учета гласных, кроме первой (для русского языка)

то есть,
Товарищество с ограниченной ответственностью => ТВРЩСТВСОГРНЧНОТВСТВНСТ
Открытое Акционерное Общество => ОТКРТАКЦНРНОБЩСТВ
далее - поиск подцепочек

Это первое, что пришло на ум из опыта решения проблемы поиска совпадения фамилий на авиабилетах (транлитерация по хитрым правилам) с реальными фамилиями на русском языке


 
Дмитрий Белькевич   (2010-04-07 00:47) [11]


> Так вот , даже на миллионных таблицах  время сканирования
> одного столбца не превышает нескольких минут.


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


 
Дмитрий Белькевич   (2010-04-07 00:52) [12]


> Это первое, что пришло на ум из опыта решения проблемы поиска
> совпадения фамилий на авиабилетах (транлитерация по хитрым
> правилам) с реальными фамилиями на русском языке


Интересно, насколько метод надёжен? У нас тоже эта проблема имеется.


 
Дмитрий Белькевич   (2010-04-07 00:54) [13]

Поиск цепочек возможен средствами базы? Или хитрый предрассчёт - занесение цепочек в базу, потом - выборка?


 
Игорь Шевченко ©   (2010-04-07 01:03) [14]

Дмитрий Белькевич   (07.04.10 00:52) [12]


> Интересно, насколько метод надёжен? У нас тоже эта проблема
> имеется.


Для нашей задачи хватило.


> Поиск цепочек возможен средствами базы? Или хитрый предрассчёт
> - занесение цепочек в базу, потом - выборка?


Нам был нужен не поиск подцепочек, а полное сравнение результатов применения операции мамбл-ванго к выбранным из базы данным. То есть, имелся поисковый реквизит, по которому выбиралось ограниченное количество фамилий, к ним применялась мамбл-ванго, к входной фамилии тоже применялась одноименная операция, а потом тупо сравнивалось - совпало/не совпало. Если не совпало - штраф :)


 
User   (2010-04-07 09:39) [15]


> >UpCharRus(), ReplaceAllStr
> Что это такое? Что-то это не то. Совсем не то. Приведи код.


Да, в этих моментах я подправил.
UpCharRus - это AnsiUpperCase
ReplaceAllStr - StringReplace(, " ", "", [rfReplaceAll]);


> Как ты перебираешь список? Не хочешь ли ты сказать, что
> у тебя до 50 000 * 50 000 = 2 500 000 000 сравнений?


Нет, в примере сравнений 50 тыс, один пробег по списку. Это пример, в реале список будет пополняться ежедневно.


> Самое правильное решение - положить все эти "стотыщпяцот"
> названий на какой-нибудь склсервер и привести его в порядок
> (по крайней мере избавиться от перестановок одинаковых слов
> и "разнокапитанистых" букав) - на "доске" сразу прояснится,
>  гад буду :)


Вот это уже интересно. Ускорится ли поиск если я при занесении в список сразу буду названий приводить в порядок?


> Т.е пройти курс [само]обучения по известным талмудам для
> тебя не хляет ?


Ну посоветуйте хотя бы книжку, статью - что читать, кого читать. Не во всех ведь книгах найдешь нужное.


 
User   (2010-04-07 10:16) [16]

Все, решил проблему. При загрузке списка сразу привел к верхнему регистру все тексты, а из функции убрал приведение к верхнему регистру. Функция в разы стала работать быстрее. Всем спасибо.


 
Sergey13 ©   (2010-04-07 10:50) [17]

> [16] User   (07.04.10 10:16)

А что это, если не секрет? Локальный вариант гугла?
Средний словарный запас человека для повседневого общения - это около 3-5 тысяч слов.
50000 выражений с ежедневным пополнением - это запись потоков мыслей? 8-)
Я бы попробовал выделять из выражений слова без последних 3-4 букв и забить их их в справочник. Выражения записал бы индексами этих слов. И по ним уже искал. Разумеется в БД.


 
User   (2010-04-07 11:52) [18]


> А что это, если не секрет? Локальный вариант гугла?


Это, что-то вроде самодельного ПО Trados. "Translation Memory", когда переводчик переводит тексты предложений, затем уже переведенные тексты заносит в базу, в след. раз что бы заново одно и тоже не переводить, программа покажет варианты переводов из БД, по проценту схожести.


 
Sergey13 ©   (2010-04-07 13:42) [19]

> [18] User   (07.04.10 11:52)

А не получится как с кэшем браузера? Типа если он небольшой, то ускоряет, а если вырос бесконтрольно - тормозит.


 
User   (2010-04-07 14:12) [20]


> А не получится как с кэшем браузера? Типа если он небольшой,
>  то ускоряет, а если вырос бесконтрольно - тормозит.


Возможно и получится. Сейчас пробую потоковое решение данной проблемы, при миллионе записей работает быстренько, дальше думаю нужно кидать в потоки.


 
Игорь Шевченко ©   (2010-04-07 14:51) [21]


> дальше думаю нужно кидать в потоки.


не нужно



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

Текущий архив: 2010.08.27;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.231 c
15-1268760103
Делфиец
2010-03-16 20:21
2010.08.27
Изучают ли Делфи в ВУЗАХ


15-1268083801
Юрий
2010-03-09 00:30
2010.08.27
С днем рождения ! 9 марта 2010 вторник


15-1266928491
Кто б сомневался
2010-02-23 15:34
2010.08.27
Интернет убил «Убийцу» (защита от пиратства)


15-1273641886
Дмитрий С
2010-05-12 09:24
2010.08.27
Что большее зло: goto или while true do ?


15-1267445916
Piter
2010-03-01 15:18
2010.08.27
Форматирование HTML кода из Delphi