Пример #1
0
    def _parse_worker(self, from_queue: Queue, to_queue: Queue):
        splitter = SentenceSplitter(self.lang)

        while True:
            # Get raw-formatted document from main process.
            document = from_queue.get()
            if document is None:
                to_queue.put(None)
                break

            # Parse the document to the plain text.
            parsed = self.parser.parse(document)

            # Divide the document into sequences with required length.
            group_sentences = []
            for paragraph in parsed.splitlines():
                for sentence in splitter.tokenize(paragraph):
                    group_sentences.append(sentence)

                    if sum(len(s) for s in group_sentences) > self.max_len:
                        to_queue.put(' '.join(group_sentences))
                        group_sentences.clear()

                # Use custom line-break token instead of `\n` which is used for
                # separating sequences.
                if group_sentences:
                    group_sentences.append(self.newline)

            # Use the remainder in dataset if its length is suitable.
            if group_sentences and group_sentences[-1] == self.newline:
                group_sentences = group_sentences[:-1]

            text = ' '.join(group_sentences)
            if len(text) > self.min_len and len(text) < self.max_len:
                to_queue.put(text)
Пример #2
0
 def __init__(self,
              parser: Parser,
              lang: str,
              min_len: int,
              max_len: int,
              newline: str = '[NEWLINE]',
              num_workers: int = 1):
     self.parser = parser
     self.min_len = min_len
     self.max_len = max_len
     self.newline = newline
     self.num_workers = num_workers
     self.splitter = SentenceSplitter(lang)
Пример #3
0
def test_korean_sentence_splitting_in_multiprocessing():
    _dummy_sentence_corpus = ('위키백과 또는 위키피디아는 누구나 자유롭게 쓸 수 있는 다언어판 인터넷 '
                              '백과사전이다. 2001년 1월 15일 지미 웨일스와 래리 생어가 시작하였으며, '
                              '대표적인 집단 지성의 사례로 평가받고 있다. 위키백과는 자유 저작물을 '
                              '보유하고 상업적인 광고가 없으며 주로 기부금을 통해 지원을 받는 비영리 '
                              '단체인 위키미디어 재단에 의해 소유되고 지원을 받고 있다. 2020년 기준으로 '
                              '영어판 600만여 개, 한국어판 517,949개를 비롯하여 300여 언어판을 합하면 '
                              '4천만 개 이상의 글이 수록되어 꾸준히 성장하고 있으며 앞으로 더 성장할 '
                              '예정이다. 위키백과의 저작권은 크리에이티브 커먼즈 라이선스(CCL)와 GNU '
                              '자유 문서(GFDL)의 2중 라이선스를 따른다. 두 라이선스 모두 자유 콘텐츠를 '
                              '위한 것으로 일정한 요건을 갖추면 사용에 제약을 받지 않는다.')

    # Create worker process function to split sentences in multi-processing.
    def _process(text: str, splitter: SentenceSplitter, queue: Queue):
        queue.put(splitter.tokenize(text))

    # Prepare processes and queue to communicate with them.
    queue = Queue()
    splitter = SentenceSplitter('ko')
    workers = [
        Process(target=_process,
                args=(_dummy_sentence_corpus, splitter, queue),
                daemon=True) for _ in range(10)
    ]

    # Start the processes.
    for w in workers:
        w.start()

    # Check if all processes split sentences correctly.
    for _ in range(10):
        assert (queue.get() == [
            '위키백과 또는 위키피디아는 누구나 자유롭게 쓸 수 있는 다언어판 '
            '인터넷 백과사전이다.', '2001년 1월 15일 지미 웨일스와 래리 생어가 시작하였으며, 대표적인 '
            '집단 지성의 사례로 평가받고 있다.', '위키백과는 자유 저작물을 보유하고 상업적인 광고가 없으며 주로 '
            '기부금을 통해 지원을 받는 비영리 단체인 위키미디어 재단에 의해 '
            '소유되고 지원을 받고 있다.', '2020년 기준으로 영어판 600만여 개, 한국어판 517,949개를 비롯하여 '
            '300여 언어판을 합하면 4천만 개 이상의 글이 수록되어 꾸준히 '
            '성장하고 있으며 앞으로 더 성장할 예정이다.',
            '위키백과의 저작권은 크리에이티브 커먼즈 라이선스(CCL)와 GNU 자유 '
            '문서(GFDL)의 2중 라이선스를 따른다.', '두 라이선스 모두 자유 콘텐츠를 위한 것으로 일정한 요건을 갖추면 '
            '사용에 제약을 받지 않는다.'
        ])
Пример #4
0
def test_english_sentence_splitting_in_multiprocessing():
    _dummy_sentence_corpus = (
        'Wikipedia is a multilingual online encyclopedia created and '
        'maintained as an open collaboration project by a community of '
        'volunteer editors using a wiki-based editing system. It is the '
        'largest and most popular general reference work on the World Wide '
        'Web. It is also one of the 15 most popular websites ranked by Alexa, '
        'as of August 2020. It features exclusively free content and no '
        'commercial ads. It is hosted by the Wikimedia Foundation, a '
        'non-profit organization funded primarily through donations.')

    # Create worker process function to split sentences in multi-processing.
    def _process(text: str, splitter: SentenceSplitter, queue: Queue):
        queue.put(splitter.tokenize(text))

    # Prepare processes and queue to communicate with them.
    queue = Queue()
    splitter = SentenceSplitter('en')
    workers = [
        Process(target=_process,
                args=(_dummy_sentence_corpus, splitter, queue),
                daemon=True) for _ in range(10)
    ]

    # Start the processes.
    for w in workers:
        w.start()

    # Check if all processes split sentences correctly.
    for _ in range(10):
        assert (queue.get() == [
            'Wikipedia is a multilingual online encyclopedia created and '
            'maintained as an open collaboration project by a community '
            'of volunteer editors using a wiki-based editing system.',
            'It is the largest and most popular general reference work on '
            'the World Wide Web.',
            'It is also one of the 15 most popular websites ranked by '
            'Alexa, as of August 2020.',
            'It features exclusively free content and no commercial ads.',
            'It is hosted by the Wikimedia Foundation, a non-profit '
            'organization funded primarily through donations.'
        ])
Пример #5
0
def test_korean_sentence_splitting():
    _dummy_sentence_corpus = ('위키백과 또는 위키피디아는 누구나 자유롭게 쓸 수 있는 다언어판 인터넷 '
                              '백과사전이다. 2001년 1월 15일 지미 웨일스와 래리 생어가 시작하였으며, '
                              '대표적인 집단 지성의 사례로 평가받고 있다. 위키백과는 자유 저작물을 '
                              '보유하고 상업적인 광고가 없으며 주로 기부금을 통해 지원을 받는 비영리 '
                              '단체인 위키미디어 재단에 의해 소유되고 지원을 받고 있다. 2020년 기준으로 '
                              '영어판 600만여 개, 한국어판 517,949개를 비롯하여 300여 언어판을 합하면 '
                              '4천만 개 이상의 글이 수록되어 꾸준히 성장하고 있으며 앞으로 더 성장할 '
                              '예정이다. 위키백과의 저작권은 크리에이티브 커먼즈 라이선스(CCL)와 GNU '
                              '자유 문서(GFDL)의 2중 라이선스를 따른다. 두 라이선스 모두 자유 콘텐츠를 '
                              '위한 것으로 일정한 요건을 갖추면 사용에 제약을 받지 않는다.')

    assert (SentenceSplitter('ko').tokenize(_dummy_sentence_corpus) == [
        '위키백과 또는 위키피디아는 누구나 자유롭게 쓸 수 있는 다언어판 '
        '인터넷 백과사전이다.', '2001년 1월 15일 지미 웨일스와 래리 생어가 시작하였으며, 대표적인 '
        '집단 지성의 사례로 평가받고 있다.', '위키백과는 자유 저작물을 보유하고 상업적인 광고가 없으며 주로 '
        '기부금을 통해 지원을 받는 비영리 단체인 위키미디어 재단에 의해 '
        '소유되고 지원을 받고 있다.', '2020년 기준으로 영어판 600만여 개, 한국어판 517,949개를 비롯하여 '
        '300여 언어판을 합하면 4천만 개 이상의 글이 수록되어 꾸준히 '
        '성장하고 있으며 앞으로 더 성장할 예정이다.', '위키백과의 저작권은 크리에이티브 커먼즈 라이선스(CCL)와 GNU 자유 '
        '문서(GFDL)의 2중 라이선스를 따른다.', '두 라이선스 모두 자유 콘텐츠를 위한 것으로 일정한 요건을 갖추면 '
        '사용에 제약을 받지 않는다.'
    ])
Пример #6
0
def test_english_sentence_splitting():
    _dummy_sentence_corpus = (
        'Wikipedia is a multilingual online encyclopedia created and '
        'maintained as an open collaboration project by a community of '
        'volunteer editors using a wiki-based editing system. It is the '
        'largest and most popular general reference work on the World Wide '
        'Web. It is also one of the 15 most popular websites ranked by Alexa, '
        'as of August 2020. It features exclusively free content and no '
        'commercial ads. It is hosted by the Wikimedia Foundation, a '
        'non-profit organization funded primarily through donations.')

    assert (SentenceSplitter('en').tokenize(_dummy_sentence_corpus) == [
        'Wikipedia is a multilingual online encyclopedia created and '
        'maintained as an open collaboration project by a community '
        'of volunteer editors using a wiki-based editing system.',
        'It is the largest and most popular general reference work on '
        'the World Wide Web.',
        'It is also one of the 15 most popular websites ranked by '
        'Alexa, as of August 2020.',
        'It features exclusively free content and no commercial ads.',
        'It is hosted by the Wikimedia Foundation, a non-profit '
        'organization funded primarily through donations.'
    ])
Пример #7
0
class ParseRawFile(Builder):
    """A builder for parsing raw-formatted corpus files.

    Args:
        parser: an implementation of raw-formatted corpus parser.
        lang: language code of the target corpus dataset.
        min_len: minimum length of each document.
        max_len: maximum length of each document.
        newline: newline token which is used for replacing the line-break
            characters.
        num_workers: number of worker processes which runs
            :meth:`parse <langumo.building.Parser.parse>`
    """
    def __init__(self,
                 parser: Parser,
                 lang: str,
                 min_len: int,
                 max_len: int,
                 newline: str = '[NEWLINE]',
                 num_workers: int = 1):
        self.parser = parser
        self.min_len = min_len
        self.max_len = max_len
        self.newline = newline
        self.num_workers = num_workers
        self.splitter = SentenceSplitter(lang)

    def _parse_worker(self, from_queue: Queue, to_queue: Queue):
        while True:
            # Get raw-formatted document from main process.
            document = from_queue.get()
            if document is None:
                to_queue.put(None)
                break

            # Parse the document to the plain text.
            parsed = self.parser.parse(document)

            # Divide the document into sequences with required length.
            group_sentences = []
            for paragraph in parsed.splitlines():
                for sentence in self.splitter.tokenize(paragraph):
                    group_sentences.append(sentence)

                    if sum(len(s) for s in group_sentences) > self.max_len:
                        to_queue.put(' '.join(group_sentences))
                        group_sentences.clear()

                # Use custom line-break token instead of `\n` which is used for
                # separating sequences.
                if group_sentences:
                    group_sentences.append(self.newline)

            # Use the remainder in dataset if its length is suitable.
            if group_sentences and group_sentences[-1] == self.newline:
                group_sentences = group_sentences[:-1]

            text = ' '.join(group_sentences)
            if len(text) > self.min_len and len(text) < self.max_len:
                to_queue.put(text)

    def _collect_worker(self, parsed: AuxiliaryFile, to_queue: Queue):
        terminated = 0
        with parsed.open('w') as fp:
            while terminated < self.num_workers:
                text = to_queue.get()
                if text is None:
                    terminated += 1
                    continue

                text += '\n' if not text.endswith('\n') else ''
                fp.write(text)

    def build(self, afm: AuxiliaryFileManager, raw: AuxiliaryFile
              ) -> AuxiliaryFile:
        parsed = afm.create()
        self.parser.prepare(raw)

        # Create processes for parsing texts in parallel and a process for
        # collecting the parsed texts and saving to the auxiliary file.
        from_queue, to_queue = Queue(), Queue()
        parsers = [Process(target=self._parse_worker,
                           args=(from_queue, to_queue),
                           daemon=True)
                   for _ in range(self.num_workers)]
        collector = Process(target=self._collect_worker,
                            args=(parsed, to_queue),
                            daemon=True)

        # Start the processes.
        print(colorful.render(f'<r>[*]</r> parse raw-formatted corpus file '
                              f'with <g>{self.parser.__class__.__name__}</g>'))

        for p in parsers:
            p.start()
        collector.start()

        # Feed the extracted raw-formatted document to each parser process.
        for document in self.parser.extract(raw):
            from_queue.put(document)
        for _ in range(self.num_workers):
            from_queue.put(None)

        # Wait for terminating the processes.
        for p in parsers:
            p.join()
        collector.join()

        return parsed
Пример #8
0
 def _process(text: str, splitter: SentenceSplitter, queue: Queue):
     queue.put(splitter.tokenize(text))