N- 그램 데이터 저장


12

나는 n 그램 데이터 를 저장하는 주제에 대해 약간 브레인 스토밍하기를 바랐습니다. 내 프로젝트에서 모든 ( n -1) 데이터 항목을 알고 있고 적용 가능한 모든 n- gram에 대해 선형 보간을 사용하여 통계적으로 n 을 추측하려는 언어 문제를 해결하려고합니다 . (예, 어휘에 따라 알려진 단어에 태그를 할당하는 태거와 알 수없는 단어의 단어 종류를 추측하는 접미사 트리 가 있습니다. 여기서 논의 된 n- gram 구성 요소는 모호함을 해결하는 작업을합니다.)

내 초기 접근 방식은 관찰 된 모든 n- gram ( n = 1..3의 경우, 모노그램, bigram, trigram) 데이터를 각 SQL 데이터베이스 에 간단히 저장 하고 하루에 호출하는 것입니다. 그러나 프로젝트의 요구 사항이 다른 벡터 길이 ( n ) 를 포함하도록 변경 될 수 있으며 많은 작업 (스키마 업데이트, 응용 프로그램 코드 업데이트 등)없이 응용 프로그램이 4 그램에 적응하기를 원합니다. 이상적으로는 단순히 코드를 많이 변경하거나 주어진 데이터 소스에서 데이터를 학습하지 않고도 응용 프로그램에서 4 그램으로 작업하도록 지시합니다.

모든 요구 사항을 요약하면 다음과 같습니다.

  • n- gram 데이터 저장 기능 (처음에는 n = {1, 2, 3}
  • 어떤 n- gram을 사용해야하는지 변경하는 기능 (애플리케이션 실행 간)
  • n- gram 데이터 를 (재) 훈련하는 기능 ( 애플리케이션 실행 간)
  • 데이터 저장소를 쿼리하는 기능 (예 : A, B, C를 관찰 한 경우 훈련 된 4-, 3-, 2-, 1- 그램 데이터 세트를 사용하여 수행 할 수있는 항목에 대해 가장 자주 관찰되는 항목을 알고 싶습니다. )

    응용 프로그램은 대부분 읽기 권한이 높고 데이터 세트는 자주 재교육되지 않습니다.

  • 이 솔루션은 .NET Framework (최대 4.0)를 사용합니다.

이제 그러한 작업에 더 적합한 디자인은 무엇입니까?

  • n 에 대해 SQL 서버 (MSSQL, MySQL 등)가 관리하는 고정 테이블 (예 : 바이그램, 트라이 그램 등 전용 테이블)
  • 또는 첫 번째 n -1을 문서의 키로 저장하는 NoSQL 문서 데이터베이스 솔루션 이며 문서 자체에는 n 번째 값과 관측 빈도 가 포함되어 있습니까?
  • 아니면 다른 것?

3
스택 오버플로에 더 적합하다고 생각합니다.
Konrad Rudolph

1
아마도 trie (접두사 트리) 데이터 구조가 요구 사항에 맞습니까?
Schedler

1
스택 오버플로 또는 cstheory.stackexchange.com을
Steve

괜찮 감사. 저기서 질문을 받도록하겠습니다.
매니

4
이 질문은 programmers.stackexchange.com에 완벽하게 적합하며 stackoverflow, IMO로 마이그레이션해서는 안됩니다. 정확히 여기에 물어봐야 할 "화이트 보드 상황"질문입니다. 자세한 내용은 메타를 확인하십시오.
user281377

답변:


8

최적의 N 범위를 알지 못한다면 분명히 변경할 수 있기를 원합니다. 예를 들어, 응용 프로그램에서 특정 텍스트가 영어 일 가능성을 예측하는 경우 N 3..5에 문자 N- 그램을 사용할 수 있습니다. (이것이 실험적으로 찾은 것입니다.)

응용 프로그램에 대한 세부 정보를 공유하지 않았지만 문제는 분명합니다. 관계형 데이터베이스 (또는 NoSQL 문서 기반 솔루션)에서 N-gram 데이터를 나타내려고합니다. 내 자신의 해결책을 제안하기 전에 다음 접근법을 살펴볼 수 있습니다.

  1. 데이터베이스에 Google ngram을 가장 잘 저장하는 방법은 무엇입니까?
  2. <n 개의 테이블 수로 데이터베이스에 n- 그램 저장
  3. 관계형 데이터베이스를 사용하여 Google Web 1T 5 그램 관리

이제 위의 링크를 읽지 않은 상태에서 각 N-gram 크기에 대해 여러 테이블을 사용하는 간단한 관계형 데이터베이스 접근 방식을 제안합니다. 필요한 최대 열을 사용하여 모든 데이터를 단일 테이블에 넣을 수 있습니다 (예 : nram_4에 bigrams 및 trigram을 저장하고 최종 열은 null로 유지). 데이터를 분할하는 것이 좋습니다. 데이터베이스 엔진에 따라 행 수가 많은 단일 테이블은 성능에 부정적인 영향을 줄 수 있습니다.

  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 데이터에 대한 쿼리에서 세 단어 를 정렬 해야하기 때문 입니다. 세 단어의 시퀀스에서 가장 가능성이 높은 다음 단어를 원한다면 bigram 데이터의 첫 번째 단어를 시퀀스의 단어 의 마지막 단어 와 비교 해야합니다.

원하는대로 무게 매개 변수를 조정할 수 있습니다. 이 예에서는 더 높은 서수 "n"그램이 더 안정적이라고 가정했습니다.

추신 : 구성을 통해 여러 ngram_N 테이블을 처리하도록 프로그램 코드를 구성합니다. ngram_5 및 ngram_6 테이블을 작성한 후 N-gram 범위 N (1..6)을 사용하도록 프로그램을 선언적으로 변경할 수 있습니다.


이 쿼리를 사용하면 여기에있는 점수 만 볼 수 있습니다. 다음 예측 단어를 어떻게 선택합니까? 문장과 가장 관련이있는 것은 무엇입니까?
TomSawyer

좋은 점 @TomSawyer. 답변에 샘플 데이터를 추가하고 가장 가능성이 높은 다음 단어를 반환하는 샘플 쿼리를 제공했습니다.
Matthew Rodatus

업데이트를위한 Tks. 그러나 여기서 주파수를 어떻게 계산할 수 있습니까? 즉 :에서 ngram_2문구의 building with주파수는 0.5입니다. 와 같은 질문입니다 @bigramWeight. freq이지만 데이터베이스를 업데이트 할 때마다 필드가 업데이트됩니다. 즉, 사용자가 더 많은 문자열을 입력하면이 문자열의 빈도가 다시 계산됩니까? 0.5는 각 문구의 총 사용 시간 또는 출현 률이 0.5 %입니까?
TomSawyer

bigramWeight 및 trigramWeight (등)는 전체 계산에서 다른 n- 그램에 가중치를 부여하는 방법입니다. 그것은 더 긴 n- 그램이 더 높은 엔트로피를 가지며 더 짧은 n- 그램보다 더 "계산"하기를 원할 수있는 간단한 방법입니다.
Matthew Rodatus

데이터베이스 업데이트 측면에서 모든 세부 사항을 다루지 않았으며 개선의 여지가 많이 있습니다. 예를 들어, ngram 테이블에 nvarchar를 저장하는 대신 단어 테이블 (word_id INT, 단어 NVARCHAR)로 토큰 화 한 다음 ngram 테이블에서 word_ids를 참조 할 수 있습니다. 재교육시 테이블을 업데이트하려면 맞습니다. 빈도 필드 만 업데이트하면됩니다.
Matthew Rodatus

3

다른 사람들이 제안하는 것과 달리 해시 맵이나 키 값 저장소보다 복잡한 데이터 구조는 피하는 것이 좋습니다.

데이터 액세스 요구 사항을 명심하십시오. a) 99 % 요청-ngram "aaa-bbb-ccc"쿼리 및 값 검색 (또는 0) b) 1 % 요청-특정 ngram 수 삽입 / 업데이트 c) 없음 (씨).

가장 효과적인 방법은 단일 조회로 검색하는 것입니다. 범위를 벗어난 (또는 이스케이프 된) 구분 기호를 사용하여 전체 n-gram을 단일 문자열 (예 : 3gram의 경우 "alpha | gamma", 유니 그램의 경우 "alpha"등)을 결합하고 ( 그 해시로). 그것은 많은 NLP 소프트웨어가 그렇게하는 방식입니다.

ngram 데이터가 작고 (1GB 미만) 메모리에 맞는 경우 오버 헤드를 피하기 위해 효율적인 프로그램 내 메모리 구조 (해시 맵, 트리, 시도 등)를 사용하는 것이 좋습니다. 플랫 파일로 직렬화 / 직렬화 해제하면됩니다. ngram 데이터가 테라 바이트 이상인 경우 여러 노드에서 분할 된 NoSQL 키-값 저장소를 선택할 수 있습니다.

추가 성능을 위해 코어 알고리즘이 (느린) 문자열을 전혀 볼 수 없도록 모든 단어를 정수 ID로 대체 할 수 있습니다. 동일한 아이디어를 구현하는 것은 약간 다릅니다.


1

가장 효율적이지는 않지만 간단하고 원하는대로 데이터베이스에 결혼했습니다.

Table: word
Colums:
word (int, primary key) - a unique identifier for each word
text (varchar) - the actual word

Table: wordpos
Columns:
document (int) - a unique identified for the document of this word
word (int, foreign key to word.word) - the word in this position
pos (int) - the position of this word (e.g., first word is 1, next is 2, ...)

wordpos는 문서와 pos에 대한 색인을 가져야합니다.

bigrams는 다음과 같습니다.

select word1.text as word1, word2.text as word2
from wordpos as pos1, wordpos as pos2, word as word1, word as word2
where pos1.document = pos2.document
      and pos1.pos = pos2.pos - 1
      and word1.word = pos1.word
      and word2.word = pos2.word

그런 다음 count ()하고 주파수와 물건으로 길을 그룹화 할 수 있습니다.

트라이 그램으로 변경하려면 word3을 포함하도록이 문자열을 쉽게 생성 할 수 있습니다.

실제로이 작업을 수행하기 전에이 작업을 수행했습니다 (SQL이 약간 녹슬 었더라도). 나는 쉽게 찾아서 디스크에서 스트리밍 할 수있는 플랫 파일 세트에 정착했습니다. Kinda는 하드웨어에 따라 더 나은 방법을 사용합니다.


1

내 응용 프로그램의 간단한 검색을 유니 그램에서 bigrams 및 trigram으로 개선하려고 노력하는 동안 본질적으로 귀하의 질문을 보았습니다.

요구 사항 중 하나가 분산 파일 시스템 또는 데이터베이스를 쿼리하는 기능인 경우에도 흥미로울 수 있습니다. Pibiri 및 Venturini 2018 "종료 N- 그램 데이터 세트를 효율적으로 처리"백서에 n-gram 데이터를 저장하는 효율적인 방법이 간략하게 설명되어 있습니다. 런타임 및 공간 조건. 그들은 https://github.com/jermp/tongrams 에서 구현을 제공했습니다.

n-gram의 각 "n"은 매우 빠른 선택 및 쿼리 기능을 갖춘 최소의 완벽한 해시 함수로 액세스되는 별도의 테이블에 보관됩니다. 테이블은 정적이며 Google n-gram 텍스트 파일 형식의 입력을 사용하여 기본 코드로 작성됩니다.

아직 코드를 사용하지는 않았지만 쿼리의 출처에 대한 공개 요구 사항으로 여러 가지 방법을 사용할 수 있습니다.

한 가지 방법 : 서블릿과 동등한 .NET이 데이터베이스 또는 데이터 저장소와 함께 사용되는 경우 저장 공간을 절약해야하는 경우 각 ngram 테이블을 이진 형식으로 데이터베이스 / 데이터 저장소에 테이블로 저장하는 것이 하나의 옵션입니다 (하나의 데이터베이스) 모든 1 그램에 대한 효율적인 ngram 코드의 결과 정적 파일에 대한 / datastore 테이블). 쿼리는 효율적인 n- 그램 코드 (서블릿이 액세스 할 수 있도록 줄 바꿈)를 호출하여 실행됩니다. 효율적인 n-gram 코드를 사용하여 분산 파일 시스템의 파일에 액세스하는 분산 데이터베이스를 만드는 해결 방법입니다. 이진 데이터베이스 / 데이터 스토어 테이블에는 각각 기본 파일 시스템의 파일 크기 제한이 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.