Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сравнение результатов поиска / 10 сообщений из 10, страница 1 из 1
19.03.2018, 22:07
    #39617093
Santa89
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Всем привет!

Допустим в таблице есть такие значения:

Код: sql
1.
2.
3.
4.
5.
6.
7.
DECLARE @T TABLE (Name varchar(20))

INSERT INTO @T
SELECT 'Михаил' UNION 
SELECT 'Михалыч' UNION
SELECT 'Михаинский' UNION
SELECT 'Михайловский' 



У меня есть строка для поиска - допустим "Михаил"
Какими средствами я могу получить данные которые бы показывали мне насколько каждая из строк в таблице @T соответствует моему поисковому слову?
Допустим первая строка это совпадение 6 символов из 6, во второй - только 4 из 6, в третьей - 5 из 6 и.т.д.

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

Как можно решать такие задачи?
Полнотекстовый индекс, подключение CLR - библиотек?
...
Рейтинг: 0 / 0
19.03.2018, 23:01
    #39617108
alexeyvg
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Santa89Как можно решать такие задачи?
Полнотекстовый индекс, подключение CLR - библиотек?SOUNDEX, DIFFERENCE, полнотекстовый индекс, подключение CLR - библиотек
...
Рейтинг: 0 / 0
20.03.2018, 10:57
    #39617310
uaggster
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Santa89подключение CLR - библиотек?
Я себе наваячил CLR сборку, и использую ее.

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports Microsoft.VisualBasic

Partial Public Class UserDefinedFunctions

    Private Structure RetCount
        Public lngSubRows As Integer
        Public lngCountLike As Integer
    End Structure

    'Нечеткое сравнение строк 
    'Аргументы: 
    '   lngMaxLen - максимальная длина сравниваемых подстрок (читайте описание алгоритма сравнения строк), 
    '   strStringMatching - первая строка,
    '   strStringStandart - вторая строка, 
    '   lngCase - тип сравнения (без учёта - 0, с учётом регистра - 1)
    'Назначение: Нечеткое сравнение двух строк 
    'Возвращает: Возвращает коэффициент совпадения строк от 0 до 100 
    '   (0 - строки не совпадают, 100 - полное совпадение)
    'Алгоритм сравнения строк Функция нечёткого сравнения использует в качестве аргументов две строки и параметр сравнения - максимальную длину
    'сравниваемых подстрок. Результатом работы функции является число, лежащее в пределах от 0 до 1. 0 соответствует полному 
    'несовпадению двух строк, а 1 - полной (в определённом ниже смысле) их идентичности. Сравнение строк происходит по следующей схеме. 
    'Пусть, например, в качестве аргументов заданы две строки "test" и "text" и некоторая максимальная длина подстрок, скажем, 4. 
    'Функция сравнения составляет все возможные комбинации подстрок с длиной вплоть до указанной и подсчитывает их совпадения в двух сравниваемых строках. 
    'Количество совпадений, разделённое на число вариантов, объявляется коэффициентом схожести строк и выдаётся в качестве результата работы функции. 

    <Microsoft.SqlServer.Server.SqlFunction()>
    Public Shared Function IndistinctMatching(MaxLen As SqlInt32, StringMatching As SqlString, StringStandart As SqlString, MatchingCase As SqlInt32) As SqlInt32
        Dim gret As RetCount
        Dim tret As RetCount
        Dim lngCurLen As Integer

        If MaxLen.IsNull Or MatchingCase.IsNull Or StringMatching.IsNull Or StringStandart.IsNull Then
            Return SqlInt32.Null
        End If

        If MaxLen = 0 Or CType(StringMatching, String).Length = 0 Or CType(StringStandart, String).Length = 0 Then
            IndistinctMatching = 0
            Exit Function
        End If

        Dim _CompareMethod As CompareMethod
        If MatchingCase = 0 Then _CompareMethod = CompareMethod.Text Else _CompareMethod = CompareMethod.Binary

        gret.lngCountLike = 0
        gret.lngSubRows = 0
        For lngCurLen = 1 To CType(MaxLen, Integer)
            tret = MatchingStrings(CType(StringMatching, String), CType(StringStandart, String), lngCurLen, _CompareMethod)
            gret.lngCountLike = gret.lngCountLike + tret.lngCountLike
            gret.lngSubRows = gret.lngSubRows + tret.lngSubRows
            tret = MatchingStrings(CType(StringStandart, String), CType(StringMatching, String), lngCurLen, _CompareMethod)
            gret.lngCountLike = gret.lngCountLike + tret.lngCountLike
            gret.lngSubRows = gret.lngSubRows + tret.lngSubRows
        Next lngCurLen
        If gret.lngSubRows = 0 Then
            Return 0
        End If
        Return CType((gret.lngCountLike / gret.lngSubRows) * 100, SqlInt32)
    End Function

    Private Shared Function MatchingStrings(strA As String, strB As String, lngLen As Integer, lngCase As CompareMethod) As RetCount
        Dim tret As RetCount
        Dim y As Integer, z As Integer
        Dim strta As String
        Dim strtb As String

        For z = 0 To strA.Length - lngLen
            strta = strA.Substring(z, lngLen)
            For y = 0 To strB.Length - lngLen
                strtb = strB.Substring(y, lngLen)
                If StrComp(strta, strtb, lngCase) = 0 Then
                    tret.lngCountLike = tret.lngCountLike + 1
                    Exit For
                End If
            Next y
            tret.lngSubRows = tret.lngSubRows + 1
        Next z
        MatchingStrings.lngCountLike = tret.lngCountLike
        MatchingStrings.lngSubRows = tret.lngSubRows
    End Function

    'Дистанция Левенштейна
    '"Наивный" алгоритм из Викиучебника
    'Сравнение без учета регистра
    <Microsoft.SqlServer.Server.SqlFunction()>
    Public Shared Function LevenshteinDistance(source As SqlString, target As SqlString) As SqlInt32

        'Если одна из строк неизвестна - результат неизвестен
        If source.IsNull Or target.IsNull Then
            Return SqlInt32.Null
        End If

        Dim l1 As Integer = CType(source, String).Length
        Dim l2 As Integer = CType(target, String).Length

        ' Если одна из строк пустая - результат - размер непустой строки
        If l1 = 0 Or l2 = 0 Then
            Return Math.Max(l1, l2)
        End If

        Dim m(l1, l2) As Integer
        Dim diff As Integer

        For i As Integer = 0 To l1
            m(i, 1) = i
        Next

        For j As Integer = 0 To l2
            m(1, j) = j
        Next

        For i As Integer = 1 To l1
            For j As Integer = 1 To l2
                If CType(source, String)(i - 1) = CType(target, String)(j - 1) Then diff = 0 Else diff = 1
                m(i, j) = Math.Min(Math.Min(m(i - 1, j) + 1, m(i, j - 1) + 1), m(i - 1, j - 1) + diff)
            Next
        Next

        Return m(l1, l2)
    End Function

    'Дистанция Дамерау-Левенштейна
    '"Наивный" алгоритм из Викиучебника
    'Сравнение без учета регистра
    <Microsoft.SqlServer.Server.SqlFunction()>
    Public Shared Function DamerauLevenshteinDistance(source As SqlString, target As SqlString) As SqlInt32

        'Если одна из строк неизвестна - результат неизвестен
        If source.IsNull Or target.IsNull Then
            Return SqlInt32.Null
        End If

        Dim l1 As Integer = CType(source, String).Length
        Dim l2 As Integer = CType(target, String).Length

        ' Если одна из строк пустая - результат - размер непустой строки
        If l1 = 0 Or l2 = 0 Then
            Return Math.Max(l1, l2)
        End If

        Dim h(l1 + 2, l2 + 2) As Integer
        Dim INF As Integer = l1 + l2

        h(0, 0) = INF

        For i As Integer = 0 To l1
            h(i + 1, 1) = i
            h(i + 1, 0) = INF
        Next

        For j As Integer = 0 To l2
            h(1, j + 1) = j
            h(0, j + 1) = INF
        Next

        Dim sd As New SortedDictionary(Of Char, Integer)
        For Each letter As Char In CType(source, String) & CType(target, String)
            If Not sd.ContainsKey(letter) Then sd.Add(letter, 0)
        Next

        For i As Integer = 1 To l1
            Dim DB As Integer = 0
            For j As Integer = 1 To l2
                Dim i1 As Integer = sd(CType(target, String)(j - 1))
                Dim j1 As Integer = DB
                If CType(source, String)(i - 1) = CType(target, String)(j - 1) Then
                    h(i + 1, j + 1) = h(i, j)
                    DB = j
                Else
                    h(i + 1, j + 1) = Math.Min(h(i, j), Math.Min(h(i + 1, j), h(i, j + 1))) + 1
                End If
                h(i + 1, j + 1) = Math.Min(h(i + 1, j + 1), h(i1, j1) + (i - i1 - 1) + 1 + (j - j1 - 1))
            Next
            sd(CType(source, String)(i - 1)) = i
        Next
        Return h(l1 + 1, l2 + 1)
    End Function

    'Инкапсулирует Regex.Replace
    <Microsoft.SqlServer.Server.SqlFunction()>
    Public Shared Function RegexReplace(source As SqlString, pattern As SqlString) As SqlString
        If source.IsNull Or pattern.IsNull Then
            Return SqlString.Null
        End If
        Return Text.RegularExpressions.Regex.Replace(source.ToString, pattern.ToString, String.Empty)
    End Function

End Class



Для эпизодических, не требовательных к производительности задач - вполне прокатывает.
...
Рейтинг: 0 / 0
20.03.2018, 11:46
    #39617371
Minamoto
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Santa89, это называется "Нечеткий поиск", один из алгоритмов, которые часто используется - это метод N-грам.
Я когда то сам реализовывал, но не публиковал нигде, ссылку не дам, но вот по поиску такой вариант находится:

https://social.technet.microsoft.com/wiki/contents/articles/33419.sql-server-implementation-of-n-gram-search-index.aspx
...
Рейтинг: 0 / 0
20.03.2018, 12:10
    #39617390
aleksrov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Minamoto,

А я ссылку дам :) Хотя писал не я.
https://sqlperformance.com/2017/09/sql-performance/sql-server-trigram-wildcard-search
...
Рейтинг: 0 / 0
20.03.2018, 17:15
    #39617711
Santa89
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Ребят, супер, спасибо!
Сейчас начну вникать...
...
Рейтинг: 0 / 0
20.03.2018, 17:58
    #39617736
Santa89
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Нашел интересный коммент с Хабра:
Код: powershell
1.
Большой минус триграмм — на коротких словах (5 символов) они работают неадекватно при такой популярной опечатке, как перепутанные символы, например: 'table' % 'tbale' = 0.2. 
...
Рейтинг: 0 / 0
20.03.2018, 18:35
    #39617754
Santa89
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
uaggster,

а почему именно CLR? Ведь такой же алгоритм можно наваять на TSQL, даже на StackOverflow есть примеры, легче поддерживать было бы...
...
Рейтинг: 0 / 0
22.03.2018, 15:41
    #39618988
Santa89
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
aleksrow,

описанный метод плох тем, что он просто выводит результаты поиска в строку, но не ранжирует эти результаты по релевантности
...
Рейтинг: 0 / 0
22.03.2018, 15:53
    #39618999
iap
iap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сравнение результатов поиска
Много было тут таких тем. Вот одна из них:
Расстояние между строками
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сравнение результатов поиска / 10 сообщений из 10, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]