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

Вниз

Быстрый поиск комбинации строк в массиве   Найти похожие ветки 

 
Юрий Зотов ©   (2015-05-23 19:49) [0]

Java.

В памяти лежит массив записей (неотсортированный, но если надо, то можно и отсортировать). Записей в массиве порядка миллиона. Каждая запись содержит 3 раздельные строки (ФИО).

Еще в памяти есть входные ФИО (тоже 3 раздельные строки). Задача - найти в массиве все записи, у которых ФИО совпадают со входными ФИО.

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

Дополнительная информация:
1. Все строки уже в верхнем регистре.
2. Отчество может быть пустым, фамилия и имя всегда заполнены.
3. Букву Ё считаем буквой Е.

Спасибо заранее. Я знаю, что All может все.


 
Юрий Зотов ©   (2015-05-23 20:02) [1]

То есть, нужно некое подобие такого запроса:

select ... from ... where
     translate(upper(LastName), "Ё", "Е") = :param1 -- фамилия
and -- то же самое для имени и отчества

Собственно, исходная информация из таблицы БД и берется, но медленно ( в таблице есть индекс по ФИО, но translate и upper его убивают). База - DB2.


 
Kerk ©   (2015-05-23 20:14) [2]

Чем тут не подходит обычная хэш-таблица?


 
Jeer ©   (2015-05-23 20:19) [3]

Юр, что-то непонятна постановка.
1. Запись, это есть и строка.
Сущности Ф.И.О в строке (записи) могут быть разнесены по полям (колонкам) записи.
Ты об этом?

2. При чем тут какая-то "память" и DB2?
Данные лежат в БД? Тогда все остальное - особенности.


 
Rouse_ ©   (2015-05-23 20:21) [4]

FTS на данные (а-ля индекс) и всех делоф


 
Rouse_ ©   (2015-05-23 20:23) [5]

Юр уйди от баз - у тебя же РО как я понял, там вме в разы проще со скоростью


 
Rouse_ ©   (2015-05-23 20:26) [6]

Просто попиариться - выборка данных по введенному слову менее полутора секунд, общий обьем базы за 40 гектаров


 
Jeer ©   (2015-05-23 21:19) [7]

Ну да, и поиск/выборка 2 килозаписей приведет к 1.5*2000 = 3000 сек, почти час.


 
Юрий Зотов ©   (2015-05-23 21:44) [8]

> Rouse_ ©   (23.05.15 20:26) [6]

У меня поисковых слов не одно, а комбинация из трех. И таких входных комбинаций 10 тысяч - то есть, поиск среди миллиона записей должен быть повторен 10 тысяч раз. Сейчас я это делаю за 50 минут, а хочется за 10.


 
Kerk ©   (2015-05-23 21:51) [9]


> Юрий Зотов ©   (23.05.15 21:44) [8]

10 тыс обращений к хеш-таблице - это точно быстрее 50 минут.


 
junglecat ©   (2015-05-23 21:56) [10]

а если сделать индексируемую вьюху уже с translate & upper?


 
кгшзх ©   (2015-05-23 22:10) [11]

Удалено модератором


 
Pavia ©   (2015-05-23 22:24) [12]

Тут типичная поисковая задача.

По алгоритмам.
1) Линейный поиск  O(N)
2) Бинарный поиск O(Log(N))
3) индексный поиск O(1)

По структурам
1) Массив O(N)
2) Хэш таблица O(1)
3) Дерево O(k*Log(N))

Для ускорения применяют индексирование. Т.е. Создание дополнительной структуры данных для ускорения поиска.

1) Индекс по ключу.
2) Суффиксное дерево
3) Обратный индекс.

Всё остальное является комбинацией всего выше перечисленного. В зависимости от требуемой скорости и доступного объема памяти.
Индекс можно сжимать. Обычно используют только дельта кодирование.
А для ключей суффиксное дерево.
В сжатом виде индекс обычно не превосходит 30%.

Для борьбы с Е,Ё во время построения индекса идёт обработка данных - лематизация. Который упрощает слова, до их основы.

Для 1 миллиона вообще сложная артиллерия не нужна. У меня на Delphi линейный поиск отлично отрабатывает за 150-60 мс. И да скорее всего у Вас проблема со скоростью вывода, а не поиска. Так что вам надо проверить. Нет ли лишних накладных расходов. Для Java думаю вам надо будет просто ускорить в 10 раз.
Достаточно проиндексировать по первой букве. Или использовать хэширование по фамилии что тоже будет быстрым. А далее линейным поиском.


 
D.N. Polezhaev ©   (2015-05-23 22:50) [13]

Что-то какой то простой вопрос от дяди Юры, потрепаться что ли ))

Давайте выступлю капитаном.

Данная задача в базах данных в чистом виде называется джойном или соединением по русски.

https://ru.m.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D1%81%D0%BE%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F_(%D0%A1%D0%A3%D0%91%D0%94)

Есть три классических алгоритма соединения.

дядя Юра говорит о том что соединение вложенными циклами работает долго - не удивительно, оно такое.

Остается попробовать соединение хешем или слиянием отсортированных списков. Если сортировать как пишет дядя Юра проблем нету - то последний способ конечно даст самый фантастишь по скорости  - параллельно бегаем синхронно по двум отсортированным спискам.

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

Можно все это мутить самостоятельно в памяти, но я не понимаю зачем. Уверен, что дб2 в курсе про эти методы соединения и так.

Остается вопрос насчет тормозов функции преобразовния данных. Ну дык и постройте индекс по этой функции, если дб2 умеет строить индексы по функциям. Тогда условие джойна соединения будет

Translate(записьИзБольшойТаблицы) = Translate(записьИзМаленькойТаблицы)

И чтобы Translate был под индексом и там, и там.

Если же по функциям индекс строить не умеет, то денормализация данных и завести колонку с данными для сравнения, где все уже приведено.

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


 
Pavia ©   (2015-05-23 22:56) [14]


> У меня поисковых слов не одно, а комбинация из трех. И таких
> входных комбинаций 10 тысяч - то есть, поиск среди миллиона
> записей должен быть повторен 10 тысяч раз. Сейчас я это
> делаю за 50 минут, а хочется за 10.

Берёте БД. Создаёте массив индексов, сортируете его по фамилии с учётом нормировки.
По массиву индексов создадим новый массив фамилий. Делаете нормализацию фамилии. Т.е. приводите к маленьким буквам(к маленьким быстрее так как их больше) заменяете "ё" на "е".
Затем группируете фамилии, указывая порядковый номер начала и конца где фамилии в массиве индексов совпадет.
Это будет массив ключей.

При поиске будете вначале ищете фамилию в массиве ключей. Затем линейный поиск по БД через индексы.


 
Rouse_ ©   (2015-05-23 23:02) [15]

При поиисковом запросе в 50 символов на 40 гигах время выборки около 17 секунд (Несколько фраз)
FTS тебе нужен


 
Pavia ©   (2015-05-23 23:11) [16]


> При поиисковом запросе в 50 символов на 40 гигах время выборки
> около 17 секунд (Несколько фраз) FTS тебе нужен

Кстати да забыл упомянуть. Прикрутить с СУБД/БД полнотекстовый поиск(FTS). Всяк быстрее чем своё изобретать, делать. Разве что если есть проблемы с памятью и нужно сжать индекс тогда свой вариант лучше.


 
кгшзх ©   (2015-05-23 23:11) [17]

добавить индексный массив.
в котором для каждой буквы хранить границы индексов первичного массива.
для всех трех полей.
исходный массив заполнять с сортированного набора данных

я-ву я-ву взял я на ха-ля-вуууу


 
Inovet ©   (2015-05-24 04:18) [18]

Ну и я ляпну в довесок. МемориТэйбл какой-нить готовый - с индексами и шахматами, с поэтессами тоже, конечно.


 
D.N. Polezhaev ©   (2015-05-24 11:13) [19]

Причем тут вообще полнотекстовый поиск какой то бред пишите. Условия задачи вообще не в этом.


 
Rouse_ ©   (2015-05-24 11:17) [20]

Спасибо, мы оценили, особливо за условия задачи. Перечитай чтоли сам вопрос и погугли что есть FTS


 
Rouse_ ©   (2015-05-24 11:32) [21]

Юр попробую немного раскрыть тему.
С таким обьемом данных мы делали следующим образом.
При добавлении нового документа в базу каждое слово (токен) из документа добавлялось в некий аналог словаря (хэш таблицу) и с ним ассоциировалось ID документа, в котором данный токен встречается.
Сам документ сохранялся как есть + к нему писался довесок из массива уникальных токенов в том порядке как они идут в документе.

К примеру
ID токена - значение
0 - мама
1 - мыла
2 - раму

документ "мама мыла раму мама мыла раму" содержит блоб токенов вида "012012"

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

Если требовалось искать точное совпадение - начинал работать второй движок, который работает с массивом токенов, идущих в том порядке, в каком они встречаются в самом документе (тут основная задержка, но на пике выходим на 17 секунд)


 
Kerk ©   (2015-05-24 12:05) [22]


> D.N. Polezhaev

Если у человека в руках молоток, то все кажется гвоздем :)


 
Kerk ©   (2015-05-24 15:07) [23]


> Rouse_ ©   (24.05.15 11:32) [21]

Остановись на секунду. У человека три поля, в каждом из них по одному слову максимум. Всего данных - несколько десятков мегабайт максимум. Какие нафиг токены, какой нафиг полнотекстовый поиск, какие нафиг документы?  Ты ему туда еще Сфинкса предложи прикрутить, ага.

Тут только два адекватных решения, одно из них в [2], другое в [10]. В [13] - вариации. Эта задача настолько проста, что ее даже обсуждать скучно.


 
Rouse_ ©   (2015-05-24 15:30) [24]

Нет у него полей - данные в памяти :)


 
Inovet ©   (2015-05-24 15:49) [25]

Ещё раз подумал, с учётом
> в таблице есть индекс по ФИО, но translate и upper его убивают
А надо ли что-то городить в памяти, нет ли в ДБ2 возможности пострить подходящий индекс? Collate там какой-нибудь с учётом регистра и буквы "Ё". Пост 10 тоже о том.

Это всё то же продолжение любви с Пенсионным Фондом? А я сразу говорил, что проблем много, с первого взгляда неочевидных и мелких. Та же "Ё" в паспорте и "Е" в ПФ, и наоборот. "Дальновидные" разработчики её сначала запретили, потом разрешили.


 
Pavia ©   (2015-05-24 18:19) [26]


> Остановись на секунду. У человека три поля, в каждом из
> них по одному слову максимум. Всего данных - несколько десятков
> мегабайт максимум. Какие нафиг токены, какой нафиг полнотекстовый
> поиск, какие нафиг документы?  Ты ему туда еще Сфинкса предложи
> прикрутить, ага.Тут только два адекватных решения, одно
> из них в [2], другое в [10]. В [13] - вариации. Эта задача
> настолько проста, что ее даже обсуждать скучно.

Классическая заблуждение. На самом делеё всё наоборот. Хэш-таблицы не ускоряют поиск. Они ускоряют сравнения. А токены это и есть хэши. А ускоряет поиск индексирование. Вот когда токенов много там да хэши ускоряют поиск, но также в качестве токена можно использовать порядковые номера слов в словаре. При этом поиск в словаре вести линейно.

Хотя на java я бы просто создал ассоциативный массив благо реализация встроена. Да и построен этот массив на основе хэширования.

А что-бы доказать что вы ошибаетесь. Предлагаю вам самому составить полный алгоритм действия.


 
Pavia ©   (2015-05-24 18:28) [27]


> А что-бы доказать что вы ошибаетесь. Предлагаю вам самому
> составить полный алгоритм действия.

Хотя тут всего 3 слова. Так что число комбинаций мало и можно хэш-таблицы использовать.


 
MsGuns ©   (2015-05-24 18:54) [28]

Не удержусь, тоже "ляпну" :)
DB2 достаточно быстрая СУБД. Тормоз наверняка в запросе, нельзя ли его увидеть полностью. Ну и эти ё и е, нельзя ли обойтись без них - в результсете не должно быть слишком много записей - можно и на клиенте отбросить лишнее.


 
Юрий Зотов ©   (2015-05-24 20:10) [29]

Докладываю сообществу результаты.

Вначале то, о чем не упоминал ранее.

1. Обработка происходит в условиях дефицита памяти в клиенте. Поэтому лучше, конечно, проводить сравнение непосредственно на сервере, а не грузить всю кучу данных на клиент. Собственно, так изначально и делалось, но слишком медленно - почему проблема и возникла. Вариант сравнения на клиенте (почему я и написал, что все уже в памяти) рассматривался, как альтернативный, но крайне нежелательный.

2. БД чужая, я в ней не хозяин. Поэтому любое изменение в ее структуре требует согласования (которого не всегда удается достичь). И это была вторая причина для того, чтобы попытаться ускорить работу, засосав все данные одним запросом (а не 10-ю тысячами) и дальше сравнивать на клиенте. Хотя, повторюсь, этот вариант очень нежелателен.

Что в итоге было сделано.

1. Конечно, был нужен индекс. К счастью, его удалось согласовать с владельцем базы. Построил индекс, основанный на функциях replace (вместо translate) и upper. Облом - не понимает DB2 function-based индексов, ругается. Скорее всего, из-за старой версии сервера - но уж какая есть, никуда от нее не денешься.

2. В таблицу было добавлено генерируемое поле с автозаполнением. В нем - конкатенация ФИО и все те же replace и upper. По этому полю и был построен искомый индекс.

==============

Результат - 5 минут. Что даже лучше, чем хотелось.

Всем спасибо.


 
D.N. Polezhaev ©   (2015-05-24 20:54) [30]

Какой блин полнотекст.

Полнотекст - это поиск слов в неструктурированном тексте, желательно релевантно.

А тут прямое сравнение заранее типизированных структур (пусть и текстовых).

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


 
D.N. Polezhaev ©   (2015-05-24 20:58) [31]

То есть, это как вместо

CompareText(s1, s2)

Взять и заюзать регулярку зачем то.


 
jack128 ©   (2015-05-25 01:44) [32]


> Результат - 5 минут

Описка?? 5 минут или 5 секунд???


 
Германн ©   (2015-05-25 02:08) [33]


> jack128 ©   (25.05.15 01:44) [32]
>
>
> > Результат - 5 минут
>
> Описка?? 5 минут или 5 секунд???
>  

Юра мечтал о 10 минутах вместо 50 минут.:)


 
Дмитрий С ©   (2015-05-25 07:29) [34]

Поиск по хеш таблице.

Я уверен, что если бы я задал такой вопрос, тот час был бы "отправлен" учиться :)


 
Павел Калугин ©   (2015-05-25 07:51) [35]

Простите не понял. Какие хеш таблицы? Поднять на клиента несколько миллионов записей, потом построить хеш и потом осуществлять поиск - за такое решение по голове погладят разве что кирпичом.
Решение добавить индексированное поле, содержащее поисковый ключ отчасти верное. Но имеет подводные камни.
Я бы рекомендовал добавить три поля в которых держать отдельно фамилию имя и отчество в верхнем регистре и очищенных от "мусора". Мусором кроме Е признал бы И Й пробелы, дефисы запятые и т. д.
Это позволило бы эффективнее искать, к примеру,  по имени и фамилии без отчества


 
Юрий Зотов ©   (2015-05-25 09:08) [36]

>  Дмитрий С ©   (25.05.15 07:29) [34]

> если бы я задал такой вопрос, тот час был бы "отправлен" учиться :)


Открою маленький секрет. Я задаю вопросы даже не с целью получить решение (обычно оно известно заранее), а с целью как бы "спровоцировать" обсуждение задачи и получить варианты решений. Пусть даже самые, на первый взгляд, бредовые. Своего рода "мозговой штурм" получается. А если обсуждающие начинают спорить о том, какое решение лучше - так вообще прекрасно, часть моей работы по выбору решения они делают за меня. Окончательный же выбор все равно происходит после чтения документации, потому что все детали задачи знаю лишь я один.

Возможность такого "штурма" и есть то самое преимущество, которое имеет живой активный форум перед документацией. Это преимущество я просто использую. И при этом совершенно не боюсь, что меня отправят учиться. Есть много вещей которые я знаю, но есть еще больше вещей, которых я не знаю. Как и каждый человек. Поэтому, если говорят "читай то-то", то не обижаться, а благодарить надо, а если еще и ссылку дадут - так вообще прекрасно.

Кроме того, вызвав обсуждение, я получаю возможность "проговорить" задачу. От этого она становится более четкой.


 
Юрий Зотов ©   (2015-05-25 09:27) [37]

> Павел Калугин ©   (25.05.15 07:51) [35]

> Решение добавить индексированное поле, содержащее поисковый
> ключ отчасти верное. Но имеет подводные камни.


Паша, а какие ты видишь камни? Поделись, плз. Это может быть важно.


 
Дмитрий С ©   (2015-05-25 11:10) [38]


> Простите не понял. Какие хеш таблицы? Поднять на клиента
> несколько миллионов записей, потом построить хеш и потом
> осуществлять поиск

Например, завести поле с хешем фамилии и имени в таблице и индексировать его. Можно без заведения, некоторые субд такое позволяют.


> Открою маленький секрет. Я задаю вопросы даже не с целью
> получить решение (обычно оно известно заранее), а с целью
> как бы "спровоцировать" обсуждение задачи и получить варианты
> решений. Пусть даже самые, на первый взгляд, бредовые. Своего
> рода "мозговой штурм" получается. А если обсуждающие начинают
> спорить о том, какое решение лучше - так вообще прекрасно,
>  часть моей работы по выбору решения они делают за меня.
>  Окончательный же выбор все равно происходит после чтения
> документации, потому что все детали задачи знаю лишь я один.
>

Это хорошо. И хорошо, что получается. Тем не менее, меня бы все-равно отправили бы учиться :)


 
Ega23 ©   (2015-05-25 11:30) [39]


> Например, завести поле с хешем фамилии и имени в таблице
> и индексировать его.

Результат хэш-функции может быть одинаков для разных входных параметров.


 
MsGuns ©   (2015-05-25 12:49) [40]

>Павел Калугин ©   (25.05.15 07:51) [35]
>Я бы рекомендовал добавить три поля в которых держать отдельно фамилию имя и отчество в верхнем регистре и очищенных от "мусора". Мусором кроме Е признал бы И Й пробелы, дефисы запятые и т. д.
Это позволило бы эффективнее искать, к примеру,  по имени и фамилии без отчества

Невнимательно читаешь. Юра в самом начале сказал, что база - чужая.
Кроме того, тебе, как опытному разработчику, нельзя не знать, что недостаточно просто "исправить" ошибки в базе РАЗОВО, надо еще менять бизнес-правила и, соответственно, политику пользовательских приложений, через которые в базу добавляется информация. А это уже совсем иная "опера".



Страницы: 1 2 3 4 5 6 7 вся ветка

Форум: "Прочее";
Текущий архив: 2016.03.13;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.004 c
15-1435756478
xayam
2015-07-01 16:14
2016.03.13
Голография


15-1435667122
Дмитрий С
2015-06-30 15:25
2016.03.13
hex 2 bin


15-1435534940
Дмитрий С
2015-06-29 02:42
2016.03.13
Выпадающий календарь. Вопрос по дизайну.


3-1307534034
vstory
2011-06-08 15:53
2016.03.13
получить record с помощью TOracleQuery


1-1335169455
lilyalm
2012-04-23 12:24
2016.03.13
Динамическое создание формы





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