Наиболее эффективный способ индексирования слов в документе?
это возникло в другом вопросе, но я решил, что лучше задать это как отдельный вопрос. Дать большой список предложений (порядка 100 тысяч):
[
"This is sentence 1 as an example",
"This is sentence 1 as another example",
"This is sentence 2",
"This is sentence 3 as another example ",
"This is sentence 4"
]
каков наилучший способ кодирования следующей функции?
def GetSentences(word1, word2, position):
return ""
где дано два слова,word1
, word2
и position
функция должна возвращать список всех предложений, удовлетворяющих этим ограничением. Например:
GetSentences("sentence", "another", 3)
должен возвращать предложений 1
и 3
как индекс предложения. Мой текущий подход использовал такой словарь:
Index = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: [])))
for sentenceIndex, sentence in enumerate(sentences):
words = sentence.split()
for index, word in enumerate(words):
for i, word2 in enumerate(words[index:):
Index[word][word2][i+1].append(sentenceIndex)
но это быстро взрывает все непропорционально на наборе данных, который составляет около 130 МБ в размере, поскольку мой 48GB RAM исчерпан менее чем за 5 минут. Я почему-то чувствую, что это общая проблема, но не могу найти никаких ссылок на то, как это эффективно решить. Есть предложения, как к этому подойти?
2 ответов
используйте базу данных для хранения значений.
- первый добавить все предложения в одну таблицу (у них должны быть идентификаторы). Вы можете назвать его, например.
sentences
. - во-вторых,создать таблицу со словами содержится во всех предложениях (назовите его, например.
words
, дайте каждому слову идентификатор), сохраняя связь между записями таблицы предложений и записями таблицы слов в отдельной таблице (назовите ее, например.sentences_words
, он должен иметь два столбца, предпочтительноword_id
иsentence_id
). -
при поиске предложений, содержащих все упомянутые слова, ваша работа будет упрощена:
-
вы должны сначала найти записи из
words
стол, где слова именно те, которые вы ищете. Запрос может выглядеть так:SELECT `id` FROM `words` WHERE `word` IN ('word1', 'word2', 'word3');
-
во-вторых, вы должны найти
sentence_id
значения из таблицыsentences
что требуетсяword_id
значения (соответствует словам изwords
таблица). Первоначальный запрос может выглядеть так:SELECT `sentence_id`, `word_id` FROM `sentences_words` WHERE `word_id` IN ([here goes list of words' ids]);
который можно было бы упростить до этого:
SELECT `sentence_id`, `word_id` FROM `sentences_words` WHERE `word_id` IN ( SELECT `id` FROM `words` WHERE `word` IN ('word1', 'word2', 'word3') );
отфильтровать результат в Python возвратить только
sentence_id
значения, которые имеют все необходимыеword_id
IDs вам нужно.
-
это в основном решение, основанное на хранение большого количества данных в форме, которая лучше всего подходит для этого - база данных.
EDIT:
- если вы будете искать только два слова, вы можете сделать еще больше (почти все) на СУБД стороны.
- учитывая, что вам также нужна разница в позиции, вы должны сохранить позицию слова в третьем столбце
sentences_words
таблица (назовем ее простоposition
) и при поиске соответствующих слов, вы должны рассчитать разницу этого значения, связанного с обоими словами.
вот как я это сделал в Python. Хотя, предполагая, что это нужно сделать более одного раза, СУБД является правильным инструментом для работы. Однако это, кажется, работает довольно хорошо для меня с миллионом строк.
sentences = [
"This is sentence 1 as an example",
"This is sentence 1 as another example",
"This is sentence 2",
"This is sentence 3 as another example ",
"This is sentence 4"
]
sentences = sentences * 200 * 1000
sentencesProcessed = []
def preprocess():
global sentences
global sentencesProcessed
# may want to do a regex split on whitespace
sentencesProcessed = [sentence.split(" ") for sentence in sentences]
# can deallocate sentences now
sentences = None
def GetSentences(word1, word2, position):
results = []
for sentenceIndex, sentence in enumerate(sentencesProcessed):
for wordIndex, word in enumerate(sentence[:-position]):
if word == word1 and sentence[wordIndex + position] == word2:
results.append(sentenceIndex)
return results
def main():
preprocess()
results = GetSentences("sentence", "another", 3)
print "Got", len(results), "results"
if __name__ == "__main__":
main()