Как оптимальным образом в Django проверить текст на наличие слов из базы?

Пытаюсь реализовать проверку загружаемых текстов на наличие слов из черного списка. Сам список хранится в базе и оперативно пополнятся. Сам придумал что-то вроде этого:
for i, wrd in enumerate(text.lower().split()):
  if BadWords.objects.filter(bword=wrd ).exists():
    return ....


Но тексты могут быть достаточно большими и поступать в большом количестве, нужно более быстрое решение.
  • Вопрос задан
  • 444 просмотра
Решения вопроса 1
@marazmiki
Укротитель питонов
Если абстрагироваться от базы данных, то задача выглядит слегка проще. Считайте, что есть два множества: множество плохих слов и множество слов в тексте. Остаётся определить, пересекаются ли эти множества. Если пересекаются, то как минимум одно плохое слово есть :-)

>>> a = { 1, 2, 3 }
>>> b = { 2, 3, 4 }
>>> c = { 5, 6 }
>>>
>>> a & b
{2, 3}
>>> a & c
set()


Теперь ближе к прикладной задаче. Поскольку множество "плохих слов" у нас хоть и хранится в БД (к слову, модели принято называть в единственном числе — BadWord — а не во множественном, как у Вас), но пока не происходят изменений, его можно считать статичным. Поэтому можно без зазрения совести брать это множество из кеша.

# utils.py
from django.core.cache import cache

def get_bad_words():
    return cache.get('bad_words')


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

# models.py
def set_bad_words(**kwargs):
    from django.core.cache import cache
    cache.set('bad_words', {w.bword for w in BadWords.objects.all()})

models.signals.post_save.connect(set_bad_words,  sender=BadWords)
models.signals.post_delete.connect(set_bad_words, sender=BadWords)


Теперь остаётся только преобразовать входящий текст в множество слов

И пример использования:
# utils.py

def get_words_from_text(text_string):
    return set([w for w in text_string.lower().split()])


и определять, есть ли плохие слова (т.е. пересекаются ли множества):

# utils.py

def has_bad_words(text_string):
    return bool(get_bad_words() & get_words_from_text(text_string))


В общем, пространство для рефакторинга и улучшений ещё есть (неплохо бы вычистить из текста пунктуацию, стоп-слова, лишние пробелы, сигналы перенести в apps.py согласно новым правилам application loading, а то и вовсе выкинуть их), но идея, думаю, ясна.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы