On-line: Andrey, гостей 1. Всего: 2 [подробнее..]
АвторСообщение





Пост N: 368
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 08.11.13 13:41. Заголовок: DBFNTX: как грамотно прервать работу SET FILTER ?


Добрый день

Есть некая таблица:
date D8
idx1 N5
idx2 N5
flags C5
string C80

И есть фрагмент программы:
filter_sx := "" 
SELE table
SET FILT TO IIF(LEN(filter_sx)==0,TRUE,(filter_sx $ table->str))
DBEDIT(...)

Т.е. пока в строку фильтра ничего не попало - видны все записи.
Если юзер хочет отфильтровать часть записей по содержимому строки - срабатывает фильтр.

Возникает ситуация: если таблица большая (>100 тыс записей), расположена на сервере и юзер желает увидеть какие-то "редкие" записи, процесс фильтрации начинает занимать непозволительно долгое время. Юзер понимает, что лучше набрать в фильтре что-то другое, но как остановить процесс текущей фильтрации ?

Делал так:
filter_sx := "" 
SELE table
SET FILT TO MyFilter()
DBEDIT(...)
...

FUNC MyFilter()

IF LEN(filter_sx) == 0
RETURN TRUE
ELSEIF INKEY(0) == K_ESC // юзер устал ждать ?
filter_sx := "" // выключаем фильтр
RETURN TRUE
ELSE
RETURN (filter_sx $ table->string)
ENDIF
RETURN TRUE

Но данный метод приводит вообще к чудным результатам: в 90% случаев после нажатия Esc - DBEDIT() начинает бешено прокручивать список вверх и зависает на первом элементе таблицы. Насколько понял по отладчику, что-то непонятное (для меня) происходит в недрах объекта в районе :Stabilize()

С какой стороны к этому вопросу подступиться?

PS: в Clipper было тоже самое - но когда тормозило всё, это было не так заметно, а сейчас, на фоне быстрой и адекватной работы Harbour... напрягает....

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 120 , стр: 1 2 3 4 5 6 All [только новые]





Пост N: 74
Зарегистрирован: 21.04.13
ссылка на сообщение  Отправлено: 08.11.13 14:30. Заголовок: Фильтр - через отдельный временный индекс


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

Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 75
Зарегистрирован: 21.04.13
ссылка на сообщение  Отправлено: 08.11.13 14:38. Заголовок: Аналогично - copy to () for myFilter()


Аналогично - копирование таблицы по FOR-условию, которое содержит
фильтр, бегунок (для оценки юзером прогноза завершения)
Если копирование прошло без прерывания - переоткрыть обзор на новую таблицу
(отфильтрованная часть)

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 369
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 08.11.13 15:16. Заголовок: Ну так получится, чт..


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

Например: в table->string слово "Москва" встречается в каждой десятой записи. А слово "Якутия" - один раз на 2000 записей. В случае фильтра по "Москве" отфильтруется в среднем, 200 записей, чтобы 20 из них попали на экран. А для Якутии придется ждать, пока отфильтруется 40 тысяч записей.

В случае FOR-условий и тем более, постройки индекса во всех случаях придется ждать обработки всех >100 тыс. записей...

Спасибо: 0 
ПрофильЦитата Ответить
Администратор




Пост N: 3037
Зарегистрирован: 23.05.05
ссылка на сообщение  Отправлено: 08.11.13 16:04. Заголовок: Sergy пишет: FUNC ..


Sergy пишет:

 цитата:
FUNC MyFilter() IF LEN(filter_sx) == 0 RETURN TRUE ELSEIF INKEY(0) == K_ESC // юзер устал ждать ? filter_sx := "" // выключаем фильтр RETURN TRUE ELSE RETURN (filter_sx $ table->string) ENDIF RETURN TRUE



Inkey(0) надо заменить на Inkey()
Ну и SetLastKey(0) перед фильтром не забыть поставить

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 370
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 08.11.13 16:53. Заголовок: Pasha пишет: Inkey(..


Pasha пишет:

 цитата:
Inkey(0) надо заменить на Inkey()


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


 цитата:
Ну и SetLastKey(0) перед фильтром не забыть поставить


Да, но к сожалению, это не повлияет на результат. DBEDIT() сходит с ума, если ему сначала функция фильтра выдавала FALSE, а потом на тех-же записях - неожиданно - TRUE...

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3700
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 08.11.13 17:56. Заголовок: Как вариант можно по..


Как вариант можно по этому полю сделать индекс а затем с помощью DBOI_SKIPWILD или DBOI_SKIPREGEX выбрать номера записей и все потом загнать в BM фильтр , но боюсь что с NTX он не дружит.
Можно пример глянуть в Xharbour skipeval.prg , думаю он и в Harbour будет работать.

Спасибо: 1 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3067
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 08.11.13 19:05. Заголовок: Sergy пишет: процес..


Sergy пишет:

 цитата:
процесс фильтрации начинает занимать непозволительно долгое время


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

Sergy пишет:

 цитата:
В случае FOR-условий и тем более, постройки индекса во всех случаях придется ждать обработки всех >100 тыс. записей...


Если уже есть готовое индексное выражение по одному ключу, то даже на базе 100 тыс. записей условная индексация строится МОМЕНТОМ !


Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 371
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 08.11.13 19:58. Заголовок: Dima пишет: Как вар..


Dima пишет:

 цитата:
Как вариант можно по этому полю сделать индекс а затем с помощью DBOI_SKIPWILD или DBOI_SKIPREGEX выбрать номера записей и все потом загнать в BM фильтр , но боюсь что с NTX он не дружит.


Хм, почитал dbinfo.ch - идея занятная, нужно будет попробовать

Andrey пишет:

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

Если уже есть готовое индексное выражение по одному ключу, то даже на базе 100 тыс. записей условная индексация строится МОМЕНТОМ !


Не очень понятно, если честно.
Вот есть таблица, пример в первом сообщении.
В строке длиной 80 символов юзер хочет найти ЛЮБОЕ нужное ему слово. А может быть, часть его. Оно может быть в начале, в середине и в конце строки. Как условная индексация сможет тут помочь ?

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3068
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 08.11.13 23:53. Заголовок: Sergy пишет: Как ус..


Sergy пишет:

 цитата:
Как условная индексация сможет тут помочь ?


Держи индекс по этому полю всегда открытым.
SELECT table
// открыт файл с первым индексом по полю "string"
DBSETORDER(1)

Условная индексация тогда будет типа:
cSlovo := "моск"

cIndexTo := "'это поле индекса по базе для сортировки/ ставь сам любое поле"
cFileIndex := "table02.cdx"
cFilter := "cSlovo $ table->string .AND. !DELETED()" // можно еще условия поставить, допустим cSlovo1 и т.д.
DELETEFILE(cFileIndex) // всегда удаляю индекс (CDX) - так как налетаешь потом на грабли
SELECT table
DBSETORDER(1)
INDEX ON &cIndexTo TO (cFileIndex) FOR &cFilter
ORDLISTADD( cFileIndex )
// здесь в раб. область базы добавляется второй индекс
DbSetOrder(2)
nKolRecords := ORDKEYCOUNT() // кол-во найденых записей
TBROWSE() //или DBEDIT()

Поставь счетчик времени и увидишь сам быстродействие.



Спасибо: 0 
ПрофильЦитата Ответить



Пост N: 76
Зарегистрирован: 21.04.13
ссылка на сообщение  Отправлено: 09.11.13 00:05. Заголовок: А упростить схему можно?


В строке длиной 80 символов юзер хочет найти ЛЮБОЕ нужное ему слово...

Видимо, нужно по-другому организовать хранение данных..
полнотекстовый поиск - это не для NTX, это интернет поисковик какой-то

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3069
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 09.11.13 11:34. Заголовок: Sergy пишет: Наприм..


Sergy пишет:

 цитата:
Например: в table->string слово "Москва" встречается в каждой десятой записи. А слово "Якутия" - один раз на 2000 записей.


petr707 пишет:

 цитата:
Видимо, нужно по-другому организовать хранение данных..


Наверно нужно делать просто справочник городов, а в базе хранить коды городов, тогда поиск будет просто "летать" !

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 372
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.11.13 12:55. Заголовок: Andrey пишет: полно..


Andrey пишет:

 цитата:
Видимо, нужно по-другому организовать хранение данных..
полнотекстовый поиск - это не для NTX, это интернет поисковик какой-то



Andrey пишет:

 цитата:
Наверно нужно делать просто справочник городов, а в базе хранить коды городов, тогда поиск будет просто "летать" !



поле table->string C80 содержит описание операции, которое формируется автоматически, но может быть скорректировано юзером.
Например:
При внутрискладском перемещении товара формируется запись: "цех -> отк" или "отк -> приемка"
При продаже товара: "магазин:Иванов (Петров)"
При поступлении: "склад << поставщик"
и тп.

к каждому этому описанию юзер может добавить что угодно, например: "/1=переделать документы", "проверить цены", "уточнить оплату" и тд и тп

"Москва" и "Якутия" были абстрактными примерами, поясняющими, что часть этих строк может встречаться чаще и фильтр по ним работает быстро, или "нормально", а если ввести часть других - начинается пипец и юзеру проще срубить задачу через диспетчер.

Так что проиндексировать точно не получится и используется полнотекстовый поиск, "как в интернете...". Поэтому ищу способ грамотно выключить фильтрацию "на лету".

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3072
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 09.11.13 13:03. Заголовок: Sergy пишет: Поэто..


Sergy пишет:

 цитата:
Поэтому ищу способ грамотно выключить фильтрацию "на лету".


Пробуй, что я предложил выше.

Спасибо: 0 
ПрофильЦитата Ответить





Пост N: 373
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.11.13 15:39. Заголовок: Andrey пишет: Пробу..


Andrey пишет:

 цитата:
Пробуй, что я предложил выше.



Andrey пишет:

 цитата:
Условная индексация тогда будет типа:
cSlovo := "моск"

cIndexTo := "'это поле индекса по базе для сортировки/ ставь сам любое поле"
cFileIndex := "table02.cdx"
cFilter := "cSlovo $ table->string .AND. !DELETED()" // можно еще условия поставить, допустим cSlovo1 и т.д.
DELETEFILE(cFileIndex) // всегда удаляю индекс (CDX) - так как налетаешь потом на грабли
SELECT table
DBSETORDER(1)
INDEX ON &cIndexTo TO (cFileIndex) FOR &cFilter


Один юзер хочет прямо сейчас найти "Моск", юзер на соседнем компе - "Якут" в тоже самое время.
Через минуту первому потребовалось "Санкт-П", а другому - "Казань". Через пару минут дальше - "Иваново". Третий юзер в тоже самое время начал искать "Владивосток".

Перестраивать индекс каждый раз?


 цитата:
Поставь счетчик времени и увидишь сам быстродействие


Понятно, что после создания индекса все "залетает"... Но так ведь его создать сначала нужно, те обработать >100 тыс записей. А это время, причем при всех вариантах - максимально долгое из возможных.

Или я что-то не так понял ?

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3703
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 09.11.13 15:52. Заголовок: Sergy пишет: Так чт..


Sergy пишет:

 цитата:
Так что проиндексировать точно не получится и используется полнотекстовый поиск, "как в интернете...". Поэтому ищу способ грамотно выключить фильтрацию "на лету".



Забей на такую методу
Вот тебе живой пример и тормозов ни каких и все влет пашет.

 
#include "dbinfo.ch"
REQUEST BMDBFNTX
Proc main()
FIELD F1
local cPattern
local amas:={}
RDDSETDEFAULT( "BMDBFNTX" )

aeval(directory("_tst.*"),{|x|ferase(x[1])})
dbCreate("_tst", {{"F1", "C", 20, 0}})
USE _tst
while lastrec()<100000
dbappend()
F1 := strzero(recno(),10)+chr(recno()%26+asc("A"))
enddo
INDEX ON F1 TO _tst
dbcommit()

cPattern:="*101*A"
dbgotop()
if !eof() .and. ! WildMatch(cPattern, ordkeyval())
dborderinfo(DBOI_SKIPWILD,,,cPattern)
endif
while !eof()
if WildMatch(cPattern, ordkeyval())
aadd(amas,recno())
endif
dborderinfo(DBOI_SKIPWILD,,,cPattern)
enddo
// а вот тут в своей проге ты можешь вернуться на нужный тебе индекс
BM_DBSETFILTERARRAY(amas)
browse()


return


или можно так и будет еще быстрее
 
cRegex:=".*101.*A"
cRegex:=HB_REGEXCOMP(cRegex)

dbgotop()
while !eof()
if HB_REGEXHAS(cRegEx,ordkeyval())
aadd(amas,recno())
endif
dborderinfo(DBOI_SKIPREGEX,,,cRegex)
enddo
BM_DBSETFILTERARRAY(amas)
browse()





Спасибо: 1 
ПрофильЦитата Ответить





Пост N: 374
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.11.13 17:15. Заголовок: Dima пишет: REQUES..


Dima пишет:

 цитата:
REQUEST BMDBFNTX


Никогда не сталкивался с таким зверем. Погуглил на этом форуме и в интернете - мало информации.
Подтолкните в правильном направлении плиз.

Спасибо.


Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3704
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 09.11.13 17:35. Заголовок: Sergy Тема есть про..


Sergy
Тема есть про BMDBFCDX в твоем случае BMDBFNTX
http://clipper.borda.ru/?1-4-0-00000808-000-0-0-1363106357

А вообще harbour\contrib\rddbm\

ЗЫ
То есть если умалчиваемым RDD сделать BMDBFNTX то все будет работать как и работало но добавятся
новые возможности с BITMAP фильтрами.

Спасибо: 1 
ПрофильЦитата Ответить





Пост N: 375
Зарегистрирован: 08.07.06
ссылка на сообщение  Отправлено: 09.11.13 19:13. Заголовок: Dima Спасибо, оказы..


Dima
Спасибо, оказывается, интересная штука! Пошел плотно изучать.



Может кому-то будет интересно - вот что надумал. Если нельзя менять SET FILTER "на лету", значит нужно проанализировать - откуда сейчас идет вызов.
 
filter_sx := ""
SELE table
SET FILT TO MyFilter()
DBEDIT(...)
...

FUNC MyFilter()
LOCAL ps:=ProcStack() // получаем стек процедур в виде строки

IF LEN(filter_sx) == 0
RETURN TRUE
ENDIF

IF INKEY() == K_ESC // юзер устал ждать ?
IF ("STAB" $ ps) .OR. ("SKIPPED" $ ps)
// СЕЙЧАС НЕЛЬЗЯ !
ELSE
filter_sx := "" // выключаем
RETURN TRUE
ENDIF
ENDIF

RETURN (filter_sx $ table->string)

Работает четко - вырубает фильтр без косяков.
Параллельно мониторю стек вызовов. Если окажется еще что-то, кроме "STABILIZE", "FORCESTABLE" и "SKIPPED", что приводит к зацикливанию - легко добавить в условие.

Спасибо: 0 
ПрофильЦитата Ответить
постоянный участник




Пост N: 3074
Зарегистрирован: 12.09.06
ссылка на сообщение  Отправлено: 10.11.13 06:30. Заголовок: Dima пишет: То есть..


Dima пишет:

 цитата:
То есть если умалчиваемым RDD сделать BMDBFNTX то все будет работать как и работало но добавятся
новые возможности с BITMAP фильтрами.


Если база открыта рабочей программой RDDCDX, можно ли открывать эту базу с помощью BMDBFCDX только для поиска ?
Косяков никаких не будет ?

И еще вопрос про поиск для BMDBFCDX:
Есть в базе поля FIO1, FIO2, FIO3 .... FIO12 (C 45)
Как организовать поиск сразу по всем полям ?
SET FILTER тормозит... Да и условие на 12 полей зашкаливает...

Спасибо: 0 
ПрофильЦитата Ответить
администратор




Пост N: 3705
Зарегистрирован: 17.05.05
ссылка на сообщение  Отправлено: 10.11.13 13:27. Заголовок: Andrey пишет: Если ..


Andrey пишет:

 цитата:
Если база открыта рабочей программой RDDCDX, можно ли открывать эту базу с помощью BMDBFCDX только для поиска ?


А зачем так поступать. Сразу дефолтным делай BMDBFCDX , все будет работать как и работало + доп возможности с фильтрами.
А вообще если шибко надо то да можно открыть ту же базу в новой рабочей области с BMDBFCDX.
Потести в общем ;)

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 120 , стр: 1 2 3 4 5 6 All [только новые]
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 368
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет