Зважаючи на те, що ви не знаєте оптимального діапазону N, ви, безумовно, хочете мати можливість його змінити. Наприклад, якщо ваша програма передбачає ймовірність того, що певний текст є англійською мовою, ви, ймовірно, хочете використовувати символи N-грам для N 3..5. (Це ми знайшли експериментально.)
Ви не поділилися деталями своєї заявки, але проблема досить зрозуміла. Ви хочете представити N-грамові дані у реляційній базі даних (або на базі документа, що базується на документі). Перш ніж запропонувати власне рішення, ви можете поглянути на такі підходи:
- Як найкраще зберігати ngram Google в базі даних?
- Зберігання n-грамів у базі даних у <n кількості таблиць
- Керування 5-грамовою Google Web 1T за допомогою реляційної бази даних
Тепер, не прочитавши жодного з перерахованих вище посилань, пропоную простий, реляційний підхід до бази даних, використовуючи кілька таблиць, по одній для кожного розміру N-грам. Ви можете помістити всі дані в одну таблицю з максимально необхідними стовпцями (тобто зберігати біграми та триграми в ngram_4, залишаючи кінцеві стовпці нульовими), але я рекомендую розділити дані. Залежно від двигуна вашої бази даних, одна таблиця з великою кількістю рядків може негативно впливати на продуктивність.
create table ngram_1 (
word1 nvarchar(50),
frequency FLOAT,
primary key (word1));
create table ngram_2 (
word1 nvarchar(50),
word2 nvarchar(50),
frequency FLOAT,
primary key (word1, word2));
create table ngram_3 (
word1 nvarchar(50),
word2 nvarchar(50),
word3 nvarchar(50),
frequency FLOAT,
primary key (word1, word2, word3));
create table ngram_4 (
word1 nvarchar(50),
word2 nvarchar(50),
word3 nvarchar(50),
word4 nvarchar(50),
frequency FLOAT,
primary key (word1, word2, word3, word4));
Далі я надішлю вам запит, який поверне найімовірніше наступне слово з усіх ваших таблиць ngram. Але спочатку ось декілька зразкових даних, які слід вставити у вищезазначені таблиці:
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'building', N'with', 0.5)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'hit', N'the', 0.1)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'man', N'hit', 0.2)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'bat', 0.7)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'building', 0.3)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'the', N'man', 0.4)
INSERT [ngram_2] ([word1], [word2], [frequency]) VALUES (N'with', N'the', 0.6)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'building', N'with', N'the', 0.5)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'hit', N'the', N'building', 0.3)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'man', N'hit', N'the', 0.2)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'building', N'with', 0.4)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'the', N'man', N'hit', 0.1)
INSERT [ngram_3] ([word1], [word2], [word3], [frequency]) VALUES (N'with', N'the', N'bat', 0.6)
INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'building', N'with', N'the', N'bat', 0.5)
INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'hit', N'the', N'building', N'with', 0.3)
INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'man', N'hit', N'the', N'building', 0.2)
INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'building', N'with', N'the', 0.4)
INSERT [ngram_4] ([word1], [word2], [word3], [word4], [frequency]) VALUES (N'the', N'man', N'hit', N'the', 0.1)
Для запиту найбільш ймовірного наступного слова, ви б використовували такий запит.
DECLARE @word1 NVARCHAR(50) = 'the'
DECLARE @word2 NVARCHAR(50) = 'man'
DECLARE @word3 NVARCHAR(50) = 'hit'
DECLARE @bigramWeight FLOAT = 0.2;
DECLARE @trigramWeight FLOAT = 0.3
DECLARE @fourgramWeight FLOAT = 0.5
SELECT next_word, SUM(frequency) AS frequency
FROM (
SELECT word2 AS next_word, frequency * @bigramWeight AS frequency
FROM ngram_2
WHERE word1 = @word3
UNION
SELECT word3 AS next_word, frequency * @trigramWeight AS frequency
FROM ngram_3
WHERE word1 = @word2
AND word2 = @word3
UNION
SELECT word4 AS next_word, frequency * @fourgramWeight AS frequency
FROM ngram_4
WHERE word1 = @word1
AND word2 = @word2
AND word3 = @word3
) next_words
GROUP BY next_word
ORDER BY SUM(frequency) DESC
Якщо ви додасте більше таблиць ngram, вам потрібно буде додати ще один пункт UNION до вищезазначеного запиту. Ви можете помітити, що в першому запиті я використовував word1 = @ word3. А у другому запиті word1 = @ word2 AND word2 = @ word3. Це тому, що нам потрібно вирівняти три слова в запиті для даних ngram. Якщо ми хочемо, щоб, найімовірніше, було наступне слово для послідовності з трьох слів, нам потрібно перевірити перше слово в даних біграми проти останнього слова слів у послідовності.
Ви можете налаштувати вагові параметри за своїм бажанням. У цьому прикладі я припускав, що більш високі порядкові "n" грами будуть більш надійними.
PS Я би структурував програмний код для обробки будь-якої кількості таблиць ngram_N через конфігурацію. Після створення таблиць ngram_5 та ngram_6 ви можете декларативно змінити програму для використання діапазону N-грамів N (1..6).