Оптимизация фильтра в BROWSE

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8024
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 28 раз
Поблагодарили: 94 раза

Оптимизация фильтра в BROWSE

Сообщение Игорь Столяров »

Привет всем !

Разговоры про вечные глюки C7, если честно порядком надоели .... :(
Давненько мы не обсуждали что-нибудь по программированию ! :)

Вопрос следующий.

Есть список (BROWSE) с несколькими символьными колонками из БД TPS (FIELD1, FIELD2, FIELD3 ...) и есть поле (LOC:FILTER), в котором пользователь задает произвольную символьную строку. Задача - отфильтровать в BROWSE все строки с вхождением этой строки в нескольких колонках (т.е. просто контекстный поиск по строке в списке).
Я сейчас в качестве фильтра задаю следующую строку:

~Clip(Loc:FILTER) Or InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1) & Clip(FIELD2) & Clip(FIELD3)),1)

Работает прекрасно. Но я не уверен что это оптимальный вариант по скорости выполнения (тормозит на больших списках и при работе в локальной сети).
Есть ли варианты или предложения как можно отимизировать фильтр для решения такой задачи ?

Заранее спасибо за любое мнение ! :)
Make Clarion Great Again ! 😎
Аватара пользователя
Admin
Администратор
Сообщения: 4010
Зарегистрирован: 05 Июль 2005, 15:59
Откуда: Хабаровск
Благодарил (а): 53 раза
Поблагодарили: 33 раза
Контактная информация:

Re: Оптимизация фильтра в BROWSE

Сообщение Admin »

Игорь Столяров писал(а):Есть ли варианты или предложения как можно отимизировать фильтр для решения такой задачи ?
C инстрингом и без SQL, боюсь без вариантов.

P.S. Кстати я бы еще предложил обсудить варианты типа SQLite, c условием легкой интеграции. Не хватает легкого SQL, без инсталяции сервака и т.д.
Рай совершает ошибки ничуть не реже чем ад. Просто у него хорошая пресса
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8024
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 28 раз
Поблагодарили: 94 раза

Re: Оптимизация фильтра в BROWSE

Сообщение Игорь Столяров »

Admin писал(а):C инстрингом и без SQL, боюсь без вариантов.
Есть еще вариант поиска с использованием Match() - но там тормоза вообще полные ... :(
Make Clarion Great Again ! 😎
Amike34
Бывалый
Сообщения: 52
Зарегистрирован: 03 Август 2005, 19:06
Откуда: г. Чебоксары

Re: Оптимизация фильтра в BROWSE

Сообщение Amike34 »

Игорь Столяров писал(а):Привет всем !

Я сейчас в качестве фильтра задаю следующую строку:

~Clip(Loc:FILTER) Or InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1) & Clip(FIELD2) & Clip(FIELD3)),1)

Работает прекрасно. Но я не уверен что это оптимальный вариант по скорости выполнения (тормозит на больших списках и при работе в локальной сети).
Есть ли варианты или предложения как можно отимизировать фильтр для решения такой задачи ?

Заранее спасибо за любое мнение ! :)
Если без сцепления попробовать?
~Clip(Loc:FILTER)
Or (Clip(Loc:FILTER) And InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1)),1))
Or (Clip(Loc:FILTER) And InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD2)),1))
Or (Clip(Loc:FILTER) And InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD3)),1))

или написать User Function или ROUTINE
if ~Clip(Loc:FILTER)
result = true
elsif InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1)),1)
result = true
elsif InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD2)),1)
result = true
elsif InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD3)),1)
result = true
end
!!! или в этой User Function или ROUTINE логику InString самому написать -
т.е. оптимизировать поиск указанных в Loc:FILTER символов в этих 3-х полях
Аватара пользователя
WadimZapara
Активист
Сообщения: 181
Зарегистрирован: 11 Июнь 2008, 12:11
Откуда: Тамбов

Re: Оптимизация фильтра в BROWSE

Сообщение WadimZapara »

Игорь Столяров писал(а):Я сейчас в качестве фильтра задаю следующую строку:
~Clip(Loc:FILTER) Or InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1) & Clip(FIELD2) & Clip(FIELD3)),1)
Работает прекрасно.
Вопрос: а вообще-то это правильно?
Ну я имею в виду случай, когда начало строки <Loc:FILTER> совпало с концом <FIELD1>, а конец <Loc:FILTER> совпал с началом <FIELD2>.
Это же ведь не значит, что Loc:FILTER содержится в FILTER1 или FILTER2.
Или такого не бывает?, или это тоже правильно?
Компьютер имеет то преимущество перед мозгом, что им пользуются...
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8024
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 28 раз
Поблагодарили: 94 раза

Re: Оптимизация фильтра в BROWSE

Сообщение Игорь Столяров »

WadimZapara писал(а):Это же ведь не значит, что Loc:FILTER содержится в FILTER1 или FILTER2. Или такого не бывает?, или это тоже правильно?
Я для вопроса немного упростил фильтр, убрав несущественные детали. Рабочий вариант выглядит как:

~Clip(Loc:FILTER) Or InString(Upper(Clip(Loc:FILTER)),Upper(Clip(FIELD1) & '|' & Clip(FIELD2) & '|' & Clip(FIELD3)),1)
Amike34 писал(а):или в этой User Function или ROUTINE логику InString самому написать - т.е. оптимизировать поиск указанных в Loc:FILTER символов в этих 3-х полях
Полей не три, а по разному. Да и что-то мне подсказывает, что любой рукописный вариант Instring вряд ли будет работать быстрее встроенной функции, реализованной на уровне RTL ...
Make Clarion Great Again ! 😎
Аватара пользователя
WadimZapara
Активист
Сообщения: 181
Зарегистрирован: 11 Июнь 2008, 12:11
Откуда: Тамбов

Re: Оптимизация фильтра в BROWSE

Сообщение WadimZapara »

А если, действительно, функция (перегружаемая):

Код: Выделить всё

  MAP
IsInStrings       Function(String ForLike, String s1), Byte
IsInStrings       Function(String ForLike, String s1, String s2), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8, String s9), Byte
IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8, String s9, String s10), Byte
  END

IsInStrings       Function(String ForLike, String s1) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s6, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s6, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s7, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s6, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s7, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s8, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8, String s9) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s6, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s7, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s8, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s9, 1, 1) Then ret += 1
    End
  Return(ret)

IsInStrings       Function(String ForLike, String s1, String s2, String s3, String s4, String s5, String s6, String s7, String s8, String s9, String s10) !, Byte
ret Byte(FALSE)
  Code
    If    InString(ForLike, s1, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s3, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s4, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s5, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s6, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s7, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s8, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s9, 1, 1) Then ret += 1
    ElsIf InString(ForLike, s10, 1, 1) Then ret += 1
    End
  Return(ret)
возможно - оно эффективнее так
или число проверяемых полей тоже динамически изменяется и на этапе компиляции неизвестно?
или число проверяемых полей может быть слишком велико?
Компьютер имеет то преимущество перед мозгом, что им пользуются...
Amike34
Бывалый
Сообщения: 52
Зарегистрирован: 03 Август 2005, 19:06
Откуда: г. Чебоксары

Re: Оптимизация фильтра в BROWSE

Сообщение Amike34 »

WadimZapara писал(а):А если, действительно, функция (перегружаемая):
..
IsInStrings Function(String ForLike, String s1, String s2) !, Byte
ret Byte(FALSE)
Code
If InString(ForLike, s1, 1, 1) Then ret += 1
ElsIf InString(ForLike, s2, 1, 1) Then ret += 1
End
Return(ret)
...
Тогда, возможно, еще крохи оптимизации привнесет следующее:

LenForLike = Len(left(clip(ForLike))) ! это вычисляем 1 раз где-то раньше
далее ...
If InString(ForLike[1 : LenForLike], s1, 1, 1) Then ret += 1
ElsIf InString(ForLike[1 : LenForLike], s2, 1, 1) Then ret += 1
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3285
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 48 раз
Контактная информация:

Re: Оптимизация фильтра в BROWSE

Сообщение Дед Пахом »

Может, какую библиотеку RegEx заюзать?
С уважением, ДП
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8024
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 28 раз
Поблагодарили: 94 раза

Re: Оптимизация фильтра в BROWSE

Сообщение Игорь Столяров »

Хорошо. Зайдем с другой стороны на вопрос ....
Функция Instring() является единственным вариантом (или самым оптимальным вариантом) для контекстного поиска по строке ?
Make Clarion Great Again ! 😎
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3285
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 48 раз
Контактная информация:

Re: Оптимизация фильтра в BROWSE

Сообщение Дед Пахом »

Игорь Столяров писал(а):Хорошо. Зайдем с другой стороны на вопрос ....
Функция Instring() является единственным вариантом (или самым оптимальным вариантом) для контекстного поиска по строке ?
Если тупо искать полное соответствие, то наверно да.
С уважением, ДП
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 8024
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 28 раз
Поблагодарили: 94 раза

Re: Оптимизация фильтра в BROWSE

Сообщение Игорь Столяров »

Дед Пахом писал(а):Если тупо искать полное соответствие, то наверно да.
А если не тупо ? ;) Есть варианты ?
Make Clarion Great Again ! 😎
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3285
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 15 раз
Поблагодарили: 48 раз
Контактная информация:

Re: Оптимизация фильтра в BROWSE

Сообщение Дед Пахом »

Игорь Столяров писал(а):
Дед Пахом писал(а):Если тупо искать полное соответствие, то наверно да.
А если не тупо ? ;) Есть варианты ?
Тут 2 варианта: тупо или нет :D Тупо - instring, "нетупо" - нечёткий поиск (поиск по созвучию и т.д.) - instring никак не катит.
С уважением, ДП
БАИ
Посетитель
Сообщения: 25
Зарегистрирован: 09 Октябрь 2009, 13:05

Re: Оптимизация фильтра в BROWSE

Сообщение БАИ »

хз, пойдет ли такое для tps
Есть у меня брауз abc на 3000 строчек таблицы, открывается это все не постранично, а полностью заливается пользователю в queue:browse:1
после ввода пользователем фильтрующего значения запускаю цикл

Код: Выделить всё

 FuzzyMatcher.SetOption(MatchOption:NoCase, 1)        !set for case insensitive search
 FuzzyMatcher.SetOption(MatchOption:WordOnly, 1)
 if flt='' then return level:benign. !  выскочим
 i#=records(queue:browse:1)
 if i# 
     loop k#=0 to i#
         get(Queue:Browse:1,i#-k#)
         if fuzzyMatch(flt,Queue:Browse:1.scr_descr)<50 then delete(Queue:Browse:1).
     end
 end
Так как после этого цикла у меня остается записей надцать в списке, я беру их id и засовываю в sql фильтр(Думается sqlfilter можно безболезненно поменять на setfilter.) и рефрешу окно:

Код: Выделить всё

i#=records(queue:browse:1)
 if i#  
     BRW1::View:Browse{prop:sqlfilter}=''
     k#=0
     loop i# times
        k#+=1
        get(queue:browse:1,k#)
        BRW1::VIEW:BROWSE{PROP:SQLFILTER}=choose(BRW1::VIEW:BROWSE{prop:sqlfilter}='','',BRW1::VIEW:BROWSE{prop:sqlfilter}&',')
        BRW1::VIEW:BROWSE{prop:sqlfilter}=BRW1::VIEW:BROWSE{prop:sqlfilter} & queue:browse:1.Таблица:id
     end
    BRW1::VIEW:BROWSE{prop:sqlfilter}='A.ID in ('&BRW1::VIEW:BROWSE{prop:sqlfilter}&')'
    BRW1.resetqueue(1)
 else
!пустой фильтр
 end
На моей проге выигрыш по скорости получается тем лучше, чем точнее вводит запрос пользователь.Минусы- каждый раз при открытии приходится выкачивать весь список полностью. Плюсы- пока идет обработка очереди, пользователя можно занять чемнибудь (по идее поможет yield и message с цитатой c bash.org.ru)
PS критика приветствуется - опыта то нету
Ответить