Свист, возвращающий пустые значения

Я использую Whoosh для индексации и поиска различных текстов в различных кодировках. При выполнении поиска по моим индексированным файлам, однако, некоторые из результатов поиска не отображаются в выходных данных, использующих функцию "выделения". У меня такое чувство, что это связано с ошибками кодирования, но я не могу понять, что может помешать отображению всех результатов. Я был бы очень благодарен за любой свет, который другие могут пролить на эту тайну.

Вот скрипт, который я использую для создания моего индекса, а вот файлы, которые я индексирую:

from whoosh.index import create_in
from whoosh.fields import *
import glob, os, chardet

encodings = ['utf-8', 'ISO-8859-2', 'windows-1250', 'windows-1252', 'latin1', 'ascii']

def determine_string_encoding(string):
    result = chardet.detect(string)
    string_encoding = result['encoding']
    return string_encoding

#specify a list of paths that contain all of the texts we wish to index
text_dirs = [

"C:\Users\Douglas\Desktop\intertextuality\sample_datasets\hume",
"C:\Users\Douglas\Desktop\intertextuality\sample_datasets\complete_pope\clean"

]

#establish the schema to be used when storing texts; storing content allows us to retrieve hightlighted extracts from texts in which matches occur
schema = Schema(title=TEXT(stored=True), path=ID(stored=True), content=TEXT(stored=True))

#check to see if we already have an index directory. If we don't, make it
if not os.path.exists("index"):
    os.mkdir("index")
ix = create_in("index", schema)

#create writer object we'll use to write each of the documents in text_dir to the index
writer = ix.writer()

#create file in which we can write the encoding of each file to disk for review
with open("encodings_log.txt","w") as encodings_out:

    #for each directory in our list
    for i in text_dirs:

        #for each text file in that directory (j is now the path to the current file within the current directory)
        for j in glob.glob( i + "\\*.txt" ):

            #first, let's grab j title. If the title is stored in the text file name, we can use this method:
            text_title = j.split("\\")[-1]

            #now let's read the file
            with open( j, "r" ) as text_content:
                text_content = text_content.read()

                #use method defined above to determine encoding of path and text_content
                path_encoding = determine_string_encoding(j)
                text_content_encoding = determine_string_encoding(text_content)

                #because we know the encoding of the files in this directory, let's override the previous text_content_encoding value and specify that encoding explicitly
                if "clean" in j:
                    text_content_encoding = "iso-8859-1"

                #decode text_title, path, and text_content to unicode using the encodings we determined for each above
                unicode_text_title = unicode(text_title, path_encoding)
                unicode_text_path = unicode(j, path_encoding)
                unicode_text_content = unicode(text_content, text_content_encoding)

                #use writer method to add document to index
                writer.add_document( title = unicode_text_title, path = unicode_text_path, content = unicode_text_content )

#after you've added all of your documents, commit changes to the index
writer.commit()

Этот код, кажется, индексирует тексты без каких-либо проблем, но когда я использую следующий скрипт для анализа индекса, я получаю три пустых значения в выходном файле out.txt - первые две строки пусты, а шестая строка пуста, но я ожидаю, что эти три строки будут непустыми. Вот скрипт, который я использую для разбора индекса:

from whoosh.qparser import QueryParser
from whoosh.qparser import FuzzyTermPlugin
from whoosh.index import open_dir
import codecs

#now that we have an index, we can open it with open_dir
ix = open_dir("index")

with ix.searcher() as searcher: 
    parser = QueryParser("content", schema=ix.schema)

    #to enable Levenshtein-based parse, use plugin
    parser.add_plugin(FuzzyTermPlugin())

    #using ~2/3 means: allow for edit distance of two (where additions, subtractions, and insertions each cost one), but only count matches for which first three letters match. Increasing this denominator greatly increases speed
    query = parser.parse(u"swallow~2/3")
    results = searcher.search(query)

    #see see whoosh.query.phrase, which describes "slop" parameter (ie: number of words we can insert between any two words in our search query)

    #write query results to disk or html
    with codecs.open("out.txt","w") as out:

        for i in results[0:]:    

            title = i["title"]
            highlight = i.highlights("content")
            clean_highlight = " ".join(highlight.split())

            out.write(clean_highlight.encode("utf-8") + "\n")

Если кто-нибудь может подсказать причины, по которым эти три ряда пусты, я был бы бесконечно благодарен.

1 ответ

Решение

Святая Моли, я бы понял это! Кажется, что некоторые из моих текстовых файлов (включая оба файла с "hume" в пути) превысили порог, который управляет поведением создания индекса Whoosh. Если кто-то пытается проиндексировать файл, который слишком велик, Whoosh, кажется, сохраняет этот текст как строковое значение, а не как значение Юникода. Таким образом, предполагая, что у вас есть индекс с полями "путь" (путь к файлу), "заголовок" (заголовок файла), "контент" (содержимое файла) и "кодировка" (кодировка текущего файла), можно проверить правильно ли проиндексированы файлы в этом индексе, запустив скрипт, подобный следующему:

from whoosh.qparser import QueryParser
from whoosh.qparser import FuzzyTermPlugin
from whoosh.index import open_dir
import codecs

#now that we have an index, we can open it with open_dir
ix = open_dir("index")

phrase_to_search = unicode("swallow")

with ix.searcher() as searcher: 
    parser = QueryParser("content", schema=ix.schema)

    query = parser.parse( phrase_to_search )
    results = searcher.search(query)

    for hit in results:    
        hit_encoding = (hit["encoding"])

        with codecs.open(hit["path"], "r", hit_encoding) as fileobj:
            filecontents  = fileobj.read()
            hit_highlight = hit.highlights("content", text=filecontents)
            hit_title     = (hit["title"])

            print type(hit_highlight), hit["title"]

Если какое-либо из напечатанных значений имеет тип "str", то кажется, что маркер обрабатывает часть назначенного файла как строку типа, а не как юникод.

Вот два способа исправить эту проблему: 1) Разделите ваши большие файлы (размером более 32 КБ) на более мелкие файлы (каждый из которых должен содержать < 32 КБ) и проиндексируйте эти файлы меньшего размера. Этот подход требует большего курирования, но обеспечивает разумную скорость обработки. 2) Передайте параметр в вашу переменную результатов, чтобы увеличить максимальное количество символов, которое можно сохранить как Unicode и, таким образом, в приведенном выше примере правильно распечатать на терминале. Чтобы реализовать это решение в приведенном выше коде, можно добавить следующую строку после строки, которая определяет results:

results.fragmenter.charlimit = 100000

Добавление этой строки позволяет печатать любые результаты из первых 100000 символов назначенного файла на терминал, хотя это значительно увеличивает время обработки. В качестве альтернативы можно полностью удалить ограничение на количество символов, используя results.fragmenter.charlimit = None хотя это действительно увеличивает время обработки при работе с большими файлами...

Другие вопросы по тегам