Учитывая, что вы не будете знать оптимальный диапазон N, вы определенно захотите его изменить. Например, если ваше приложение прогнозирует вероятность того, что определенный текст является английским, вы, вероятно, захотите использовать N-граммы символов для N 3..5. (Это то, что мы обнаружили экспериментально.)
Вы не поделились информацией о вашем приложении, но проблема достаточно ясна. Вы хотите представить N-граммовые данные в реляционной базе данных (или решении на основе документов NoSQL). Прежде чем предлагать собственное решение, вы можете взглянуть на следующие подходы:
- Как лучше хранить Google Ngrams в базе данных?
- Хранение n-граммов в базе данных в количестве <n таблиц
- Управление Google Web 1T 5-грамм с реляционной базой данных
Теперь, не прочитав ни одной из вышеуказанных ссылок, я предлагаю простой подход к реляционной базе данных, использующий несколько таблиц, по одной для каждого размера 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 через конфигурацию. Вы можете декларативно изменить программу на использование диапазона N-грамм N (1..6) после создания таблиц ngram_5 и ngram_6.