Запрос комментарий: код на Python, который ищет слова запроса в заданной текста


У меня есть этот код, который выглядит для слова запроса в заданной текста. Я предобработки дай текст и хранить его в перевернутом-индекс (словарь с Слово как ключ и позицию в тексте, значение). Поиск слов запроса, затем становится контант время работы.

Приведенный ниже код также выводит окружающего текста, который содержит максимальное количество запросов.

Пожалуйста, помогите мне понять недостатки (стиль кодирования, именования, проблемы с производительностью) кодекса.

# -*- coding: cp1252 -*-
from collections import defaultdict

class c_Highlight():
"""Highlight Class to find and print relevant snippet of a text"""

Grammar_Suffix = ['ing' ,'ly', 'ed', 'ious', 'ies', 'ive', 'es', 's', 'ment']
Punctuation = [',', '!', '.', '?', '"', '\n']

def __init__(self):
    self.InvertedIndex = defaultdict( list )

def m_Read_File( self, f_name ):
    """
        Function to Read a file, if the text is to be read from file
        Args: FileName
        Returns: List of words
    """

    list_words = []
    try:
        f = open(f_name)
        for line in f:
            line = line.strip()
            list_words.extend( line.split())
        f.close()
    except IOError as (errno, strerror):
        print "File I/O Error({0}): {1}".format(errno, strerror)
        exit(0)

    return list_words

def __m_Stem( self, word ):
    """
        Function to remove Suffix from the end of a word.
        Input: Word
        Returns: Cropped Word
    """
    word = word.lower()
    for suffix in c_Highlight.Grammar_Suffix: 
        if word.endswith(suffix):
            word = word[:-len(suffix)]
            break
    for punctuation in c_Highlight.Punctuation:
        while word.endswith(punctuation):
            word = word[:-len(punctuation)]

    return word #can be empty list

def m_Create_InvertedIndex( self, words ):
    """
        Function to parse the input words and store them in a InvertedIndex
        The Key is the word itself and Value is the position of the word in the text
        Input: List of Words
        Return: None
    """
    idx = 0
    for word in words:
        word = self.__m_Stem(word)
        self.InvertedIndex[word].append(idx)
        idx = idx+1

def m_Search_Query( self, search_query, length ):
    """
        Function to search for query words in the InvertedIndex
        Input: List of query words, and the number of words in the text
        Return: Integer List of length same as the number of words. Each index indicates
        if the word is present in the query or not. So if List[i]==0, the word is not present
        and if List[i]==2, then the 2nd word in the query is present at location i in the input text.           
    """
    words_present = []
    idx = 1
    for x in range(length):
        words_present.append(0)
    for word in search_query:
        word = self.__m_Stem(word)
        if word in self.InvertedIndex:
            for word_index in self.InvertedIndex[word]:
                words_present[word_index] = idx
            idx = idx + 1
    return words_present


def m_Find_Snippet( self, words_present, num_words, MaxWindow ):
    """
        Function to find a snippet of input text with has the most number of query
        words present.
        Input: Integer List, length, and number of words to be present in the snippet
        Return: begin, end position of the window and the count of query words present
        in the snippet
    """
    begin = 0
    count = 0
    end = 0
    max_count = -1
    Snippet_End = 0
    Snippet_Begin = 0
    num_words = len(words_present)
    try:
        while begin < num_words:
            if words_present[begin]!=0:
                count = 0
                end = begin
                end_done = min((MaxWindow + begin), num_words)
                while end < end_done:
                    if words_present[end]!=0:
                        count+=1
                    end+=1

                if end == num_words:
                    end-=1
                if count > max_count:
                    max_count = count
                    Snippet_Begin = begin
                    Snippet_End = end
            begin+=1

        while Snippet_End > 0:
            if words_present[Snippet_End]!=0:
                break
            Snippet_End-=1            

    except IndexError:
        print "Tying to access out of bound index in method m_Find_Snippet"

    return Snippet_Begin, Snippet_End, max_count


def m_Sentence_End( self, word ):
    for suffix in ['.', '!', '?']:
        if word.endswith(suffix):
            return 1
    return 0

def m_Print_Snippet( self, Snippet_Begin, Snippet_End, raw_data, words_present ):
    """
        Function to generate the output text. 
        Input: begin and end position of snippet
        Returns: Beautifies the snippet and returns the new start and end position of the snippet 
    """

    start = Snippet_Begin
    new_start = Snippet_Begin
    end = Snippet_End
    num_sentence = 0
    flag = 0
    num_words = len(raw_data)
    try:
        start_done = min( 20, Snippet_Begin )
        while (Snippet_Begin - start) <= start_done:
            if self.m_Sentence_End( raw_data[start] ):
                num_sentence += 1
                new_start = start+1
            if num_sentence == 2:
                flag = 1
                break
            start -= 1

        if flag == 1:
            Snippet_Begin = start + 1
        elif flag == 0:
            if start_done == Snippet_Begin:
                Snippet_Begin = start + 1
            else:
                Snippet_Begin = new_start

        num_sentence = 0
        new_end = Snippet_End
        flag = 0
        end_done = min( 20, num_words - Snippet_End )
        while (end - Snippet_End) < end_done:
            if self.m_Sentence_End( raw_data[end] ):
                num_sentence+=1
                new_end = end
            if num_sentence == 2:
                flag = 1
                break
            end += 1

        if flag == 1:
            Snippet_End = end
        elif flag == 0:
            if end_done == (num_words - Snippet_End):
                Snippet_End = num_words - 1
            else:
                Snippet_End = new_end


    except IndexError:
        print "Tying to access out of bound index in method m_Print_Snippet"

    output_text = []
    query_start = 0

    try:
        for x in range( Snippet_Begin, Snippet_End+1 ):
            if words_present[x]!=0:
                if query_start == 0:
                    output_text.append('[[HIGHLIGHT]]'+raw_data[x])
                    query_start = 1
                else:
                    output_text.append(raw_data[x])
            else:
                if query_start == 1:
                    w = output_text.pop()
                    output_text.append(w+'[[ENDHIGHLIGHT]]')
                    output_text.append(raw_data[x])
                    query_start = 0
                else:
                    output_text.append(raw_data[x])

        if words_present[x]!=0:
            w = output_text.pop()
            output_text.append(w+'[[ENDHIGHLIGHT]]')

    except IndexError:
        print "Trying to access out of bound index in method m_Print_Snippet"

    return ' '.join(output_text)


def m_Highlight_doc( doc, query ):
"""
Args:
        doc-string that is a document to be c_Highlighted
        query-string that contains the search query

Return:
        Text Snippet
"""

WINDOW_LENGTH = 35
text = doc.split()
query = query.split()
num_words = len(text)
Search = c_Highlight()
Search.m_Create_InvertedIndex(text)
words_present = Search.m_Search_Query(query, num_words)
begin, end, count = Search.m_Find_Snippet( words_present, num_words, WINDOW_LENGTH )
if count <= 0:
    return "Query Not Found"
else:
    return Search.m_Print_Snippet( begin, end, text, words_present )


1715
3
задан 28 мая 2011 в 12:05 Источник Поделиться
Комментарии
1 ответ

# -*- coding: cp1252 -*-
from collections import defaultdict

class c_Highlight():

Определена была и мы с неодобрением ненадобностью.

"""Highlight Class to find and print relevant snippet of a text"""

Grammar_Suffix = ['ing' ,'ly', 'ed', 'ious', 'ies', 'ive', 'es', 's', 'ment']
Punctuation = [',', '!', '.', '?', '"', '\n']

Официальное руководство по стилю Python рекомендует всем шапки для константы такой

def __init__(self):
self.InvertedIndex = defaultdict( list )

Официальное руководство по стилю Python рекомендует all_lower_case_with_underscores для имен переменных

def m_Read_File( self, f_name ):
"""
Function to Read a file, if the text is to be read from file
Args: FileName
Returns: List of words
"""

list_words = []
try:
f = open(f_name)
for line in f:
line = line.strip()
list_words.extend( line.split())
f.close()

Это может быть лучше, если вы используете с

with open(f_name) as f:
for line in f:
line = line.strip()
list_words.extend(line.split())

Это позволит закрыть файл, даже исключение.

    except IOError as (errno, strerror):
print "File I/O Error({0}): {1}".format(errno, strerror)
exit(0)

выход(0) означает, что программа преуспел в этом деле, это не так.

    return list_words

Поскольку эта функция не манипулировать любым объектом атрибутами, это может быть лучше в качестве отдельной функции полезности.

def __m_Stem( self, word ):
"""
Function to remove Suffix from the end of a word.
Input: Word
Returns: Cropped Word
"""
word = word.lower()
for suffix in c_Highlight.Grammar_Suffix:
if word.endswith(suffix):
word = word[:-len(suffix)]
break

Я рекомендую использовать ответным словом[:-лен(суффикс)] вместо.

    for punctuation in c_Highlight.Punctuation:
while word.endswith(punctuation):
word = word[:-len(punctuation)]

Вы не нарушаете здесь, как вы делали раньше

    return word #can be empty list

С ваших слов представляется строк, этот комментарий-это просто неправильно.

def m_Create_InvertedIndex( self, words ):
"""
Function to parse the input words and store them in a InvertedIndex
The Key is the word itself and Value is the position of the word in the text
Input: List of Words
Return: None
"""
idx = 0
for word in words:
word = self.__m_Stem(word)
self.InvertedIndex[word].append(idx)
idx = idx+1

Используйте перечислять

for idx, word in enumerate(words):
word = self.__m_Stem(word)
self.InvertedIndex[word].append(index)

Видите? намного чище.

def m_Search_Query( self, search_query, length ):
"""
Function to search for query words in the InvertedIndex
Input: List of query words, and the number of words in the text
Return: Integer List of length same as the number of words. Each index indicates
if the word is present in the query or not. So if List[i]==0, the word is not present
and if List[i]==2, then the 2nd word in the query is present at location i in the input text.
"""

Требуя передать пользователю в длину вводимого текста кажется странным. Сам класс знает длину вводимого текста, и пользователь, вероятно, нет.

    words_present = []
idx = 1
for x in range(length):
words_present.append(0)

Использование: word_present = [0] * длина создавать words_present, это будет быстрее и понятнее.

    for word in search_query:
word = self.__m_Stem(word)
if word in self.InvertedIndex:
for word_index in self.InvertedIndex[word]:
words_present[word_index] = idx
idx = idx + 1

Вы только инкремент индекса IDx , когда найдено совпадение. Это кажется странным, как я ожидал, что IDx на соответствующие индексы в search_query. Также возвращая список, как это кажется странным, так как его довольно много, как трудно найти значения в этот список как найти слова в первую очередь.

    return words_present

def m_Find_Snippet( self, words_present, num_words, MaxWindow ):
"""
Function to find a snippet of input text with has the most number of query
words present.
Input: Integer List, length, and number of words to be present in the snippet
Return: begin, end position of the window and the count of query words present
in the snippet
"""
begin = 0
count = 0
end = 0
max_count = -1
Snippet_End = 0
Snippet_Begin = 0

Руководство по стилю Python recommaeds this_style для локальных переменных.

    num_words = len(words_present)
try:
while begin < num_words:
if words_present[begin]!=0:
count = 0
end = begin
end_done = min((MaxWindow + begin), num_words)
while end < end_done:
if words_present[end]!=0:
count+=1
end+=1

Вы действительно рассчитывал, от начала до end_done использовать для петли.

                if end == num_words:
end-=1

Вы должны быть в состоянии избавиться от этого безобразия, когда вы используете выше петли

                if count > max_count:
max_count = count
Snippet_Begin = begin
Snippet_End = end

Я предлагаю реструктуризации этот код, чтобы использовать генератор. Генератор будет генерировать сниппеты начинается/заканчивается, и вызывающий код может использовать Макса, чтобы выбрать лучший.

            begin+=1

Используйте цикл для начала. Если вы окажетесь желая использовать цикл while, шлепать себя и использовать цикл for.

        while Snippet_End > 0:
if words_present[Snippet_End]!=0:
break
Snippet_End-=1

Еще раз, используйте цикл. Когда вы рассчитываете, вы должны использовать цикл for. Кроме того, сделать это, когда вы сначала создайте фрагмент, не сейчас.

    except IndexError:
print "Tying to access out of bound index in method m_Find_Snippet"

Зачем ловить ошибку индекса? В IndexError обычно указывает на ошибку в коде. Все, что вам сделать, поставив этот здесь делает код сложнее отлаживать, не показывая трассировку стека и продолжая таким образом, вы не заметили ошибку.

    return Snippet_Begin, Snippet_End, max_count

def m_Sentence_End( self, word ):
for suffix in ['.', '!', '?']:
if word.endswith(suffix):
return 1
return 0

Использовать истинные и ложные не 1 и 0.

def m_Print_Snippet( self, Snippet_Begin, Snippet_End, raw_data, words_present ):
"""
Function to generate the output text.
Input: begin and end position of snippet
Returns: Beautifies the snippet and returns the new start and end position of the snippet
"""

Вы объясните Snippet_Begin и конец фрагмента, которые были очевидны. Но вы не удосужились объяснить, что raw_data средства.

    start = Snippet_Begin
new_start = Snippet_Begin
end = Snippet_End
num_sentence = 0
flag = 0
num_words = len(raw_data)
try:
start_done = min( 20, Snippet_Begin )
while (Snippet_Begin - start) <= start_done:
if self.m_Sentence_End( raw_data[start] ):
num_sentence += 1
new_start = start+1
if num_sentence == 2:
flag = 1
break
start -= 1

Если вы должны рассчитывать, вы должны использовать цикл for! Также не используйте 1 для истинной. Я тоже очень привлекли мое внимание булевых флагов. Я думаю, что они задерживаются Гото.

        if flag == 1:

Использовать если флаг:

            Snippet_Begin = start + 1
elif flag == 0:

Если флаг может быть только истинным или ложным просто использовать еще

            if start_done == Snippet_Begin:
Snippet_Begin = start + 1
else:
Snippet_Begin = new_start

num_sentence = 0
new_end = Snippet_End
flag = 0
end_done = min( 20, num_words - Snippet_End )
while (end - Snippet_End) < end_done:
if self.m_Sentence_End( raw_data[end] ):
num_sentence+=1
new_end = end
if num_sentence == 2:
flag = 1
break
end += 1

if flag == 1:
Snippet_End = end
elif flag == 0:
if end_done == (num_words - Snippet_End):
Snippet_End = num_words - 1
else:
Snippet_End = new_end

except IndexError:
print "Tying to access out of bound index in method m_Print_Snippet"

Опять же, не делай этого. Не делай этого. НЕ ДЕЛАЙ ЭТОГО!

    output_text = []
query_start = 0

try:
for x in range( Snippet_Begin, Snippet_End+1 ):
if words_present[x]!=0:
if query_start == 0:
output_text.append('[[HIGHLIGHT]]'+raw_data[x])

Его, вероятно, быстрее использовать StringIO, а затем добавив в список

                    query_start = 1
else:
output_text.append(raw_data[x])
else:
if query_start == 1:
w = output_text.pop()
output_text.append(w+'[[ENDHIGHLIGHT]]')
output_text.append(raw_data[x])
query_start = 0
else:
output_text.append(raw_data[x])

if words_present[x]!=0:
w = output_text.pop()
output_text.append(w+'[[ENDHIGHLIGHT]]')

except IndexError:
print "Trying to access out of bound index in method m_Print_Snippet"

...

    return ' '.join(output_text)

def m_Highlight_doc( doc, query ):
"""
Args:
doc-string that is a document to be c_Highlighted
query-string that contains the search query

Return:
Text Snippet
"""

WINDOW_LENGTH = 35
text = doc.split()
query = query.split()
num_words = len(text)
Search = c_Highlight()
Search.m_Create_InvertedIndex(text)
words_present = Search.m_Search_Query(query, num_words)
begin, end, count = Search.m_Find_Snippet( words_present, num_words, WINDOW_LENGTH )
if count <= 0:
return "Query Not Found"
else:
return Search.m_Print_Snippet( begin, end, text, words_present )

m_Print_Snippet довольно сложная функция. Он может быть упрощен. Вот мой упрощенный вариант. (Его не проверял, наверное, сломана, но может дать вам подсказки о том, как можно упростить код)

def rewind_to_sentance_start(self, words, current_start):
minimum_start = max(0, current_start - 20)
num_sentence = 0
new_start = minimum_start
for possible_start in range(current_start, minimum_start, -1):
word = words[possible_start]
if self.m_Sentence_End(word):
num_sentence += 1
current_start = possible_start

if num_sentence == 2:
return possible_start + 1
return new_start

def forward_to_sentance_end(self, words, current_end):
maximum_end = min(len(words)-1, current_end + 20)
num_sentence = 0
new_end = maximum_end
for possible_end in range(current_end, minimum_end, 1):
word = words[possible_end]
if self.m_Sentence_End(word):
num_sentence += 1
current_end = possible_end

if num_sentence == 2:
return possible_end + 1
return new_end

def m_Print_Snippet( self, Snippet_Begin, Snippet_End, raw_data, words_present ):
"""
Function to generate the output text.
Input: begin and end position of snippet
Returns: Beautifies the snippet and returns the new start and end position of the snippet
"""

Snippet_Begin = rewind_to_sentance_start(raw_data, Snippet_Begin)
Snippet_End = forward_to_sentance_end(raw_data, Snippet_End)

output = StringIO.StringIO()
query_start = 0

snippet_words = raw_data[Snippet_Begin:Snippet_End]
words_present = map(bool, words_present[Snippet_Begin:Snippet_End])
# map(bool makes sure that they are really bools in there
for highlighted, data in itertools.groupby( zip(words_present, snippet_words), operator.itemgetter(0) ):
if highlighted:
output.write('[[HIGHLIGHT]]')
output.write(' '.join(word for present, word in data))
if highlighted:
output.write('[[ENDHIGHLIGHT]]')

return output.getvalue()

Примечания:


  1. Любая часть логики функции это вообще комплекс должен быть выбиты в собственную функцию.

  2. Python в модуле itertools есть много полезных инструментов для того, чтобы переместить логику вашу функцию в ваш код более понятным

4
ответ дан 28 мая 2011 в 01:05 Источник Поделиться