Dado que no conocerá el rango óptimo de N, definitivamente desea poder cambiarlo. Por ejemplo, si su aplicación predice la probabilidad de que cierto texto sea inglés, probablemente quiera usar caracteres N-gramos para N 3..5. (Eso es lo que encontramos experimentalmente).
No ha compartido detalles sobre su aplicación, pero el problema es lo suficientemente claro. Desea representar datos de N-gram en una base de datos relacional (o una solución basada en documentos NoSQL). Antes de sugerir una solución propia, es posible que desee echar un vistazo a los siguientes enfoques:
- ¿Cómo almacenar mejor los ngrams de Google en una base de datos?
- Almacenar n-gramos en la base de datos en <n número de tablas
- Administrar Google Web 1T de 5 gramos con base de datos relacional
Ahora, al no haber leído ninguno de los enlaces anteriores, sugiero un enfoque de base de datos simple y relacional utilizando múltiples tablas, una para cada tamaño de N-gram. Puede poner todos los datos en una sola tabla con las columnas máximas necesarias (es decir, almacenar bigrams y trigrams en ngram_4, dejando las columnas finales nulas), pero recomiendo particionar los datos. Dependiendo de su motor de base de datos, una sola tabla con una gran cantidad de filas puede afectar negativamente el rendimiento.
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 continuación, le daré una consulta que devolverá la siguiente palabra más probable dada todas sus tablas de ngram. Pero primero, aquí hay algunos datos de muestra que debe insertar en las tablas anteriores:
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 la siguiente palabra más probable, usaría una 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
Si agrega más tablas de ngram, deberá agregar otra cláusula UNION a la consulta anterior. Puede notar que en la primera consulta usé word1 = @ word3. Y en la segunda consulta, word1 = @ word2 AND word2 = @ word3. Eso es porque necesitamos alinear las tres palabras en la consulta para los datos de ngram. Si queremos la siguiente palabra más probable para una secuencia de tres palabras, necesitaremos verificar la primera palabra en los datos de bigramas contra la última palabra de las palabras en la secuencia.
Puede ajustar los parámetros de peso como lo desee. En este ejemplo, supuse que los "n" gramos ordinales más altos serán más confiables.
PD: Estructuraría el código del programa para manejar cualquier número de tablas ngram_N a través de la configuración. Podría cambiar declarativamente el programa para usar el rango de N-gramos N (1..6) después de crear las tablas ngram_5 y ngram_6.