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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.068 c
4-1238606535
Psycho
2009-04-01 21:22
2010.08.27
Хук на WM_DROPFILES в трей


15-1272852692
Tirael
2010-05-03 06:11
2010.08.27
как скрыть лишние интерфейсы


2-1271495387
G.I.
2010-04-17 13:09
2010.08.27
Таймер в Delphi


2-1268971257
Delphist
2010-03-19 07:00
2010.08.27
adocommand1.execute


2-1270871051
tippa
2010-04-10 07:44
2010.08.27
Synchronize и критические секции





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский