Нечёткий поиск

Clarion, Clarion 7

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

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

Нечёткий поиск

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

Привет всем !

Вопрос простой и прямой: не пробовал ли кто-нибудь реализовать нечёткий поиск (например с заданным процентом подобия) ?

1. В принципе, алгоритмика известна, но я не математик. :(
Исходники есть на Java и Python ... Может быть тема поднималась где-то в архивах ClaMag ?

2. Конкретно меня сейчас интересует вопрос поиска подобных товаров (когда их названия записывают по-разному).
Например: Сосиска в тесте, булочка с сосиской, сосиська запечённая в тесте и т.д.

3. В Clarion есть MATCH(). Опция Match:Soundex (по звучанию) не локализована, поиск по маске - это иное ...

Я не спрашиваю о готовом решении (хотя это было бы круто), но хотя бы направление туда, где рыба есть.
Что бы не идти методом познания, на основе собственных ошибок. Заранее спасибо ! :)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

Я давно пытался реализовать этот механизм для названий товаров и контрагентов. Именно в таком ключе, по проценту подобия. Делал алгоритм с разбиением на триады. Но, в целом, нормально не получилось, отлавливались только самые примитивные ситуации. В результате, просто отключил этот отчёт. Если удастся найти работающей решение, штука нужная и полезная.
C6/C11, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7494
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 18 раз
Поблагодарили: 51 раз

Нечёткий поиск

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

Спасибо ! Понял. Попробую спросить на хабе, может СуперКарл поможет ... ;)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
Ravenous
Бывалый
Сообщения: 58
Зарегистрирован: 06 Июль 2005, 14:25
Откуда: Москва
Поблагодарили: 1 раз

Нечёткий поиск

Сообщение Ravenous »

Я делал на стороне БД (MSSQL, Oracle), в PostgreSQL есть pg_trgm тоже нормально работает.
Благодарень за терпение и понимание.

Изображение
kreator
✯ Ветеран ✯
Сообщения: 5034
Зарегистрирован: 28 Май 2009, 15:54
Откуда: Москва
Благодарил (а): 7 раз
Поблагодарили: 23 раза

Нечёткий поиск

Сообщение kreator »

Логика простая. Данные должны храниться сейчас хотя бы в "формате" SQL. А там много чего есть. Если там нет, то надо теребить разработчиков таких серверов. Поиск правильно осуществлять на стороне сервера.
We are hard at work… for you. :)
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

Я несколько не так на триграммы разбивал. Надо будет попробовать алгоритм, как описано в psql, с добавлением пробелов. Так то все просто должно быть.
C6/C11, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7494
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 18 раз
Поблагодарили: 51 раз

Нечёткий поиск

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

finsoftrz писал(а): 03 Июнь 2024, 8:01 алгоритм, как описано в psql
Ссылу почитать опять засекретите ? ;)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

Игорь Столяров писал(а): 03 Июнь 2024, 8:21
finsoftrz писал(а): 03 Июнь 2024, 8:01 алгоритм, как описано в psql
Ссылу почитать опять засекретите ? ;)
В сообщении от Ravenous.
C6/C11, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7494
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 18 раз
Поблагодарили: 51 раз

Нечёткий поиск

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

Т.е. опять много шума из ничего ... :)
В сообщении ведь применение встроенных методов, а не описание алгоритма. :(
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

В начале ("Примечание") вроде все понятно написано. Не?
C6/C11, ШВС, tps/btrieve.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7494
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 18 раз
Поблагодарили: 51 раз

Нечёткий поиск

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

Ну не знаю. Наверно люди написавшие
Эта простая идея оказывается очень эффективной для измерения схожести слов на многих естественных языках.
понимают в этом. Можно попробовать сделать и посмотреть ...
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
Ravenous
Бывалый
Сообщения: 58
Зарегистрирован: 06 Июль 2005, 14:25
Откуда: Москва
Поблагодарили: 1 раз

Нечёткий поиск

Сообщение Ravenous »

Вот статья на которую опирался при написании своей реализации
https://blog.arbinada.com/ru/category/00020.html

Реализация pg_trgm
https://github.com/postgres/postgres/tr ... ib/pg_trgm
Благодарень за терпение и понимание.

Изображение
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

Накидал тест алгоритма на коленке.

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

form_r routine   !формирование отчета
  DATA
lor:queue queue, pre()
lor:idobj   long
lor:ind     long
lor:mass    string(3),dim(10000)
.
lor:symbols string(100)
lor:str     string(3)
lor:dl      long
lor:kolRep  long

lor:nameobjSel string(200)
lor:idobjSel   long
lor:indSel     long
lor:indMax     long
lor:massSel    string(3),dim(10000)
lor:massContr  long,dim(10000)

lor:i   long
lor:j   long
lor:k   long
lor:n   long

BasicProcess  BasicProcessType

  CODE

       lor:symbols='abcdefghijklmnopqrstuvwxyzабвгдеёжзийклмнопрстуфхцчшщъыьэюя0123456789'  !список анализируемых символов

       BasicProcess.Init(True,'Загрузка товаров',,,,,100,Records(tovar))
       set(tovar)
       loop
          next(tovar)
          if error()
             break
          .
          if ~BasicProcess.LoopStep()
             break
          .
          if tov:NoPost=1
             cycle
          .
          if tov:name=''
             cycle
          .

          tov:name=left(lower(tov:name))
          lor:nameobjSel=''
          lor:j=0
          loop lor:i=1 to len(clip(tov:name))
             if instring(tov:name[lor:i],clip(lor:symbols),1,1)>0
                lor:j+=1
                lor:nameobjSel[lor:j]=tov:name[lor:i]
             .
          .

          clear(lor:queue)
          lor:idobj=tov:id
          lor:dl=len(clip(lor:nameobjSel))

          lor:ind=0
          lor:k=1
          loop
             if lor:k>lor:dl
                break
             .
             lor:str=lor:nameobjSel[lor:k : lor:k+2]
             if lor:ind>9996
                break
             .
             lor:ind+=1
             lor:mass[lor:ind]='  ' & lor:str[1]
             lor:ind+=1
             lor:mass[lor:ind]=' ' & lor:str[1 : 2]
             lor:ind+=1
             lor:mass[lor:ind]=lor:str
             if lor:str[2 : 3]<>''
                lor:ind+=1
                lor:mass[lor:ind]=lor:str[2 : 3] & ' '
             .
             lor:k+=3
          .
          add(lor:queue)
       .

    BasicProcess.Kill()

    open(ProgressWindow)
    BasicProcess.Init(False,'Сопоставление',,?Progress:Thermometer,?Progress:Cancel,True,5,Records(lor:queue),?Progress:UserString)
    loop lor:i=1 to records(lor:queue)-1
       get(lor:queue,lor:i)
       if ~BasicProcess.LoopStep()
          break
       .

       lor:indSel=lor:ind
       lor:idobjSel=lor:idobj
       lor:massSel=lor:mass

       loop lor:j=lor:i+1 to records(lor:queue)
          get(lor:queue,lor:j)
          lor:kolRep=0
          lor:indMax=choose(lor:indSel>lor:ind,lor:indSel,lor:ind)
          clear(lor:massContr)
          loop lor:k=1 to lor:indSel
             loop lor:n=1 to lor:ind
                if lor:mass[lor:n]=lor:massSel[lor:k] and lor:massContr[lor:n]=0
                   lor:kolRep+=1
                   lor:massContr[lor:n]=1
                .
             .
          .
          lor:kolRep=lor:kolRep/lor:indMax*100
          if Loc:Proc<=lor:kolRep
             clear(Loc:Queue)
             Loc:IDObj1=lor:idobjSel
             Loc:IDObj2=lor:idobj
             Loc:ProcQ=lor:kolRep
             add(Loc:Queue)
          .
       .
    .

    free(lor:queue)
    BasicProcess.Kill()
    close(ProgressWindow)

search.jpg
C6/C11, ШВС, tps/btrieve.
kreator
✯ Ветеран ✯
Сообщения: 5034
Зарегистрирован: 28 Май 2009, 15:54
Откуда: Москва
Благодарил (а): 7 раз
Поблагодарили: 23 раза

Нечёткий поиск

Сообщение kreator »

Почему паштет №6 "Корона Балтики" не имеет дубликата? наверно есть ещё над чем работать.
We are hard at work… for you. :)
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 4737
Зарегистрирован: 06 Ноябрь 2014, 12:48
Благодарил (а): 10 раз
Поблагодарили: 38 раз

Нечёткий поиск

Сообщение finsoftrz »

kreator писал(а): 07 Июнь 2024, 16:02 Почему паштет №6 "Корона Балтики" не имеет дубликата? наверно есть ещё над чем работать.
Не понял.
C6/C11, ШВС, tps/btrieve.
Ответить