Como você não conhece a faixa ideal de N, você definitivamente deseja alterá-la. Por exemplo, se seu aplicativo predizer a probabilidade de um determinado texto ser inglês, você provavelmente desejaria usar o N-gramas de caracteres para N3..5. (Foi o que descobrimos experimentalmente.)
Você não compartilhou detalhes sobre seu aplicativo, mas o problema é claro o suficiente. Você deseja representar dados N-gram em um banco de dados relacional (ou solução baseada em documento NoSQL). Antes de sugerir uma solução própria, dê uma olhada nas seguintes abordagens:
- Como armazenar melhor os ngrams do Google em um banco de dados?
- Armazenando n-gramas no banco de dados em <n número de tabelas
- Gerenciamento do Google Web 1T de 5 gramas com banco de dados relacional
Agora, não tendo lido nenhum dos links acima, sugiro uma abordagem de banco de dados relacional simples usando várias tabelas, uma para cada tamanho de N-grama. Você pode colocar todos os dados em uma única tabela com o máximo de colunas necessárias (por exemplo, armazenar bigrams e trigramas no ngram_4, deixando as colunas finais nulas), mas recomendo particionar os dados. Dependendo do mecanismo do banco de dados, uma única tabela com um grande número de linhas pode afetar negativamente o desempenho.
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));
A seguir, apresentarei uma consulta que retornará a próxima palavra mais provável, considerando todas as suas tabelas ngram. Mas primeiro, aqui estão alguns dados de exemplo que você deve inserir nas tabelas acima:
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)
Para consultar a próxima palavra mais provável, use uma consulta como esta.
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
Se você adicionar mais tabelas ngram, precisará adicionar outra cláusula UNION à consulta acima. Você pode notar que, na primeira consulta, usei word1 = @ word3. E na segunda consulta, word1 = @ word2 AND word2 = @ word3. Isso ocorre porque precisamos alinhar as três palavras na consulta para os dados ngram. Se desejarmos a próxima palavra mais provável para uma sequência de três palavras, precisamos verificar a primeira palavra nos dados do bigram com a última palavra das palavras na sequência.
Você pode ajustar os parâmetros de peso conforme desejar. Neste exemplo, assumi que gramas ordinais "n" mais altos serão mais confiáveis.
PS: Eu estruturaria o código do programa para lidar com qualquer número de tabelas ngram_N via configuração. Você pode alterar declarativamente o programa para usar o intervalo N-grama N (1..6) após criar as tabelas ngram_5 e ngram_6.