gifts2017

"Глобальный" поиск (легкая замена полнотекстовому)

Опубликовал Андрей Вахрин (dolter) в раздел Администрирование - Поиск данных

Есть такая штука в Axapta, как "Глобальный поиск"... Правда я ее увидел после того, как сделал первый вариант своего, но... потом пришлось дорабатывать по аксаптовский, уж больно он мне понравился :-)
Но покажу только первый вариант.

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

Потом появилась задача так же быстро искать и контрагентов по частям наименований. [ООО "Континент" - Континент, ООО - Континент и т.д.]. Но не будешь же кучу полей добавлять в справочнике для каждой части наименования!

Выход напрашивается сам собой - регистр сведений с двумя полями: законченное слово из наименования и ссылка на объект...

А дальше пара глобальных функций и процедур :-)

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

P.S. есть возможность искать по нескольким словам (условие И); есть возможность искать по части строки ("слов*", "*лов", "*ло*")

P.P.S. зачем все это если есть полнотекстовый? а попробуйте на уже живой базе в 100 гиг его поднять... да и с обновлением динамическим потом намучаетесь... :-)

P.P.P.S. в принципе все это можно перенести и на 7.7... и не на 1С тоже...

Скачать файлы

Наименование Файл Версия Размер
Обработка 163
.epf 5,76Kb
02.07.13
163
.epf 5,76Kb Бесплатно

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Евгений Мартыненков (JohnyDeath) 09.01.10 12:44
А вот так:
SELECT *
FROM НужнаяТаблица
WHERE НужнаяТаблица.НужноеПоле LIKE '%ПодстрокаПоиска%'

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

А в твоем варианте, если завтра бухи захотят поиск по ИНН, ты быдешь в регистр и это поле заносить? И так для каждого чиха?
2. Андрей Вахрин (dolter) 09.01.10 12:50
(1) Так и было в начале... во всех формах... но на 2 млн расходных документов в год и 0,5 млн контрагентов вешалась база намертво - никто работать не мог по человечески.
А во втором решении (скорее всего буду выкладывать как платное) добавление ИНН происходит установкой одной "галки" - и можно искать одновременно и по части наименования и по ИНН.
А то, что написали вы... попробуйте найти просто "СТО" без всяких "столица", "столичный", "астория" и пр. И самое главное - ускорение поиска в десятки раз по сравнению с вашим вариантом, т.к. поиск производится по индексу (не в случае поиска типа "*ло*" :-))...
3. Сергей (Che) Коцюра (CheBurator) 09.01.10 13:09
такс... побежал за попкорном и колой
4. Валерий Гуров (Saint) 09.01.10 16:42
А что, отборы уже отменили? Я что-то пока не улавливаю, чем принципиально лучше предложенное решение по сравнению с отборами.
5. Андрей Вахрин (dolter) 09.01.10 17:12
(4) Какие отборы? О чем речь?
Если о графах отбора, то это совершенно другое решение.
Прежде чем пользоваться отбором по графе, нужно найти сам элемент (наверное :-)).
6. Валерий Гуров (Saint) 09.01.10 17:40
(5) Универсальный объект "Отбор". Отбор используется для установки и хранения условий фильтрации элементов в списках и наборах записей. Отбор элементов в списках помогает, если необходимо выбрать элементы по определенному критерию из большого списка элементов.

Это из синтакс-помошника.
7. Андрей Вахрин (dolter) 09.01.10 17:52
(6) и как он поможет мне в данной ситуации?
попробуй установить отбор по наименованию по содержит и слова не в том порядке, как они записаны в наименовании, а еще одно слово полностью, а второе с любым окончанием...
8. Валентин Терёхин (Valet) 09.01.10 18:09
(7)Что мешает добавить индекс реквизиту? И будет поиск по реквизиту с использованием индекса.
А выносить поля в регистр сведений, лишь из-за того чтобы не делать индекс по ним в реальном справочнике/документе, как то странно.

Отбор в форме списка не установишь, но ничего не мешает запрос с ПОДОБНО и со своей строкой поиска по любому реквизиту.
9. Андрей Вахрин (dolter) 09.01.10 18:16
ох-хо-хоюшки... да что за молодежь пошла такая непонятливая-то...
ладно, будет желание - потестите на скорости и нагрузки (да и на различных вариаций в возможностях поиска), а нет... так на нет и суда нет :-)
(8) при поиске по like не испольузется индекс
10. Валерий Гуров (Saint) 09.01.10 20:54
(7) Не знаю, как он поможет тебе, просто я в своей практике не встречал у пользователей необходимости в таких сложных поисковых запросах. Может пользователи не самые продвинутые, но тем не менее.
(9) Ну да, куда уж нам до седобородых старцев, умудрённых опытом. :D Может твоё решение найдёт применение в определённых ситуациях, но в целом нет необходимости выдумывать новые сущности. Естественно это только моё личное мнение. :idea:
11. Роман Ершов (MRAK) 10.01.10 11:08
(10) ну все зависит от специфики и методологии работы конкретной конторы. Думаю, иногда сабж имеет смысл.
12. Евгений Мартыненков (JohnyDeath) 10.01.10 21:00
(9)
при поиске по like не испольузется индекс

а в твоем случае поиск по '*со*' будет попадать в индекс?

А если известно начало слова, то можно построить поиск по >= и <= (или BETWEEN). Смысла выводить значения в отдельный регистр не вижу.
13. Андрей Вахрин (dolter) 11.01.10 08:58
(12) в (2) я об этом говорил (про индекс)...
не понял насчет ">= и <= (или BETWEEN") - можно пример?
14. Артур Аюханов (artbear) 11.01.10 09:58
(13) Регистр как и когда заполняется?
15. Евгений Мартыненков (JohnyDeath) 11.01.10 10:44
(13) Например, надо найти всех контрагентов, которые начинаются с 'ма'.
select descr
from Справочник_Контрагенты
where descr between 'ма' and 'маЯ'

Попали в индекс "UPPER(DESCR)"

П.С. Пишу для 7.7 под 1sqlite. На другом, к сожалению проверить не могу.
П.С.2. Если уж совсем придираться, то левую часть условия лучше всего добивать буквой "Я" до полной длины. Т.е. если длина наименования = 20, то запрос выглядит так:
select descr
from Справочник_Контрагенты
where descr between 'ма' and 'маЯЯЯЯЯЯЯЯЯЯЯЯЯЯЯЯЯЯ'
16. Андрей Вахрин (dolter) 11.01.10 12:17
(14) у меня по событию ПриЗаписи (начальное заполнение, ессесно, обработкой)
(15) о! спасибо! для поиска по началу так и сделаю (такой идеи пока не было) :-)
17. Евгений Мартыненков (JohnyDeath) 11.01.10 12:25
(16) ну так зачем регистр, если можно обойтись и без него?
18. Андрей Вахрин (dolter) 11.01.10 13:17
(17) не дописал: "для поиска по началу так и сделаю" + " в регистре" :-)
потому что... я хочу (МОГУ) искать по первым символам любого слова в строке и (или) по различным сочетаниям этих слов (с учетом того, что все они ИМЕННО в регистре проиндексированы)
19. Евгений Мартыненков (JohnyDeath) 11.01.10 13:56
Всё равно так и не понял, в чём смысл дублировать данные в отдельном регистре...
20. Андрей Вахрин (dolter) 11.01.10 14:41
(19) ок...
напиши как найти с использованием индекса (т.е. _быстро_) контрагента с наименованием
"ООО Континент-СТО" 

по строке
"СТО Континент"

без использования отдельного регистра...
21. Евгений Мартыненков (JohnyDeath) 11.01.10 14:53
(20) да, тогда никак.
А у тебя получается, что ты в ПриЗаписи разбиваешь наименования на слова и заносишь отдельными строками в регистр?

И еще вопрос. Твой регистр состоит из 2-х колонок: "Наименование" и "Объект". Теперь бухи хотят иметь быстрый поиск не только по справочнику контрагентов, но и по справочнику сотрудников. Делаем поиск по "Мажор" в итоге выпадает "ООО Мажор" из контрагентов и "Мажоров Иван Иваныч" из сотрудников?
22. Андрей Вахрин (dolter) 11.01.10 15:35
(21) в том варианте, что я выложил, для каждого объекта необходим отдельный регистр.
в варианте платном (ели выложу) общий регистр с дополнительным полем "вид объекта" - т.е. можно указывать область поиска (см.картинки)
Прикрепленные файлы:
23. Андрей Казанцев (ander_) 13.01.10 13:12
как вариант (реально работающий на 1с7.7 SQL + 1с++) на интересующий справочник/документ вешается тригер, который собирает участвующие в поиске поля в одну строку (по определенным правилам) и по ней заполняет дополнительную табличку, по которой в дальнейшем и будет идти поиск. Н.р.:
из реквизитов "ЧП Иванов" + "22-33-44" + "г.Урюпинск" получим строку
"ЧП Иванов 223344 г.Урюпинск" заполним таблицу
ид стр
' 56 ' ЧП Иванов 223344 г.Урюпинск
' 56 ' П Иванов 223344 г.Урюпинск
' 56 ' Иванов 223344 г.Урюпинск
' 56 ' Иванов 223344 г.Урюпинск
' 56 ' ванов 223344 г.Урюпинск
' 56 ' анов 223344 г.Урюпинск
' 56 ' нов 223344 г.Урюпинск
' 56 ' ов 223344 г.Урюпинск
' 56 ' в 223344 г.Урюпинск
' 56 ' 223344 г.Урюпинск
' 56 ' 223344 г.Урюпинск
' 56 ' 23344 г.Урюпинск
' 56 ' 3344 г.Урюпинск
' 56 ' 344 г.Урюпинск
' 56 ' 44 г.Урюпинск
' 56 ' 4 г.Урюпинск
' 56 ' г.Урюпинск
' 56 ' г.Урюпинск
и т.д.

потом когда пользователь вводит строку для поиска, считаем что пробел это "И", запятая "ИЛИ" и строим соответствующий запрос с использованием LIKE str+'%' (попадаем в индекс)

избыточность конечно большая, но быстродействие пока радует.
ЗЫ: Здесь вариант немного упрощенный привел.
24. Андрей Вахрин (dolter) 13.01.10 14:13
25. Вадим Никонов (V.Nikonov) 13.01.10 14:44
Я поступил проще. Самый распространённый Поиск/Отбор это по фрагменту номера документа и по Контрагенту. Для этих двух реквизитов созданы 2 дополнительных поля фильтрации, отрабатываются процедуры изменения поля Доп.Фильтра как исправление Фильтра журнала в 1С8.хх.

С номером совсем просто, можно установить отбор с критерием отбора "Содержит".

Отбор по контрагенту у нас используется через задание ссылки, но при желании можно и отрабатывать по Списку значений.
26. Андрей Вахрин (dolter) 13.01.10 15:07
27. Вадим Никонов (V.Nikonov) 13.01.10 19:11
Фрагмент кода обрабатывающий изменение Фильтра Номера:
//НВЮ/ Поиск заказа по части Номера
// Элемент - текстовое поле для отбора по фрагменту номера
Процедура ИскомыйНомерПриИзменении(Элемент)
    Если ЗначениеЗаполнено(Элемент.Значение) Тогда
        ЭтаФорма.Отбор.Номер.ВидСравнения = ВидСравнения.Содержит;
        ЭтаФорма.Отбор.Номер.Значение = Элемент.Значение;
        ЭтаФорма.Отбор.Номер.Использование = Истина;
        ЭтаФорма.Обновить();
    Иначе
        ЭтаФорма.Отбор.Номер.Значение = "";
        ЭтаФорма.Отбор.Номер.Использование = Ложь;
        ЭтаФорма.Обновить();
    КонецЕсли;
КонецПроцедуры
...Показать Скрыть
28. Андрей Вахрин (dolter) 14.01.10 08:56
29. Михаил Гомбоев (yoyoman) 06.04.12 12:00
Я делал как то так:
сч=1;
ТекстЦикл="";
Для каждого ЭлементСписка из СписокСлов цикл
	ТекстЦикл=ТекстЦикл + "
	|	И Номенклатура.Наименование ПОДОБНО &Наименование"+сч;
	сч=сч+1;
КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст="ВЫБРАТЬ
|	Номенклатура.Наименование КАК Наименование,
|	Номенклатура.Ссылка КАК Ссылка
|ИЗ
|	Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|	Номенклатура.ЭтоГруппа = ЛОЖЬ"
+ТекстЦикл+"								
|
|УПОРЯДОЧИТЬ ПО
|	Наименование";
сч=1;								 
Для каждого ЭлементСписка из СписокСлов цикл
	Запрос.УстановитьПараметр("Наименование"+сч,"%"+ЭлементСписка+"%");
	сч=сч+1;
КонецЦикла;
...Показать Скрыть

СписокСлов это массив, который собирался разбиванием строкового поля ввода пробелами
30. Михаил Гомбоев (yoyoman) 06.04.12 12:10
Такм образом "ООО Континент-СТО" достаточно легко находится через "СТО Континент"
31. Андрей Вахрин (dolter) 06.04.12 13:22
(30) yoyoman,
согласен - просто и работоспособно, но(!) скорость обработки такого запроса на больших объемах просто запредельная :(
да и под каждое текстовое поле придется писать свой запрос, т.е. ненастраиваемо
32. юрий космовский (Kosmovski) 05.02.13 19:18
StrMatch.dll - посмотри неплохая dll-ка для нечеткого поиска