Перейти к содержанию

Сравнение неоднозначных дат

При оптическом распознавании текста даты извлекаются в виде строк, формат которых не всегда очевиден. Строка 03/05/2023 может означать 3 мая (формат ДД/ММ/ГГГГ) или 5 марта (формат ММ/ДД/ГГГГ). Вместо того чтобы угадывать единственный правильный вариант, алгоритм хранит все возможные толкования и при сравнении ищет пересечение множеств.

Реализация сосредоточена в модуле date_utils.py. Подробное описание функций модуля приведено в разделе Работа с неоднозначными датами; здесь разбирается сам алгоритм и его применение во всех подсистемах.

Суть алгоритма

Шаг 1: разбор всех толкований

Для каждой строки с датой модуль определяет формат по набору регулярных выражений (точка, косая черта, тире, стандарт ГГГГ-ММ-ДД, слитная запись ГГГГММДД) и строит множество толкований.

Правила определения однозначности:

  • Если первое число больше 12 --- это точно день. Формат ДД/ММ, уверенность 1.0.
  • Если второе число больше 12 --- это точно месяц. Формат ММ/ДД, уверенность 1.0.
  • Если оба числа от 1 до 12 --- оба варианта равновероятны. Уверенность каждого 0.5.
  • Формат ГГГГ-ММ-ДД (международный стандарт) и ГГГГММДД (слитный) всегда однозначны.

Пример:

"03/05/2023" → {2023-05-03, 2023-03-05}   (оба числа ≤ 12)
"25/12/2023" → {2023-12-25}                (25 > 12 → однозначно день)
"2023-05-03" → {2023-05-03}                (стандартный формат)

Шаг 2: сравнение через пересечение

При сравнении двух дат модуль строит множества толкований для каждой и ищет пересечение:

Реестр:   "03/05/2023" → {2023-05-03, 2023-03-05}
Документ: "2023-05-03" → {2023-05-03}
Пересечение: {2023-05-03} → совпадение найдено

Если пересечение непустое --- даты считаются совпавшими. Оценка уверенности зависит от того, были ли исходные значения однозначными:

Ситуация Оценка
Обе даты однозначны, совпадение 1.0
Одна дата неоднозначна, пересечение найдено 0.95
Обе даты неоднозначны, уникальное пересечение 0.85
Пересечения нет 0.0

Шаг 3: допуск по дням

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

base_confidence × (1 − distance / tolerance × 0.2)

Каждый день отнимает до 20 % от базовой уверенности, но итоговая оценка не опускается ниже 0.8.

Пример при допуске в 1 день:

"03/05/2023" и "2023-05-04" → разница 1 день, оценка ≈ 0.8

Поддерживаемые форматы

Формат Пример Когда неоднозначен
ДД.ММ.ГГГГ 25.12.2023 Если первое число не превышает 12
ДД/ММ/ГГГГ 03/05/2023 Если первое число не превышает 12
ДД-ММ-ГГГГ 03-05-2023 Если первое число не превышает 12
ГГГГ-ММ-ДД 2023-05-03 Никогда (международный стандарт)
ГГГГММДД 20230503 Никогда
ДД.ММ.ГГ 03.05.23 Если первое число не превышает 12
ДД/ММ/ГГ 03/05/23 Если первое число не превышает 12

Для двузначных годов значения до 50 трактуются как 20XX, от 50 и выше --- как 19XX.

Обратно совместимые функции

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

  • normalize_date --- возвращает одну дату в формате ГГГГ-ММ-ДД. При неоднозначности предпочитает формат ДД/ММ. Используется при нормализации импортированных строк реестра.
  • get_all_date_normalizations --- возвращает список всех возможных нормализаций. Используется при построении указателей для многоиндексного поиска.
  • parse_date_to_datetime --- возвращает объект даты. Используется в группировке для вычисления разницы в днях.

Где используется алгоритм

Алгоритм сравнения неоднозначных дат пронизывает всю систему:

  • Группировка документов (подробнее) --- при проверке, относятся ли два документа к одной группе, даты сравниваются с учётом всех толкований. Точное совпадение даёт 30 баллов, приблизительное (±1 день) --- 20 баллов.
  • Построение указателей (подробнее) --- при загрузке документов в память для каждой даты в указатель записываются все возможные нормализации. Это позволяет находить документы за постоянное время, даже если формат даты в реестре отличается от формата в документе.
  • Сопоставление с реестром (подробнее) --- при вычислении балла совпадения по полю «дата» используется оценка уверенности (1.0, 0.95 или 0.85).
  • Импорт строк реестра (подробнее) --- при нормализации значений дат из Excel.
  • Фоновая задача поиска (подробнее) --- обработчик Celery вызывает те же функции сравнения при пакетном поиске документов.

Почему выбран подход с множествами

Альтернативный подход --- выбрать один формат (например, всегда считать ДД/ММ) --- проще в реализации, но приводит к пропускам: если в реестре дата записана как ММ/ДД, а в документе как ДД/ММ, совпадение не будет найдено.

Подход с множествами толкований избегает этой проблемы: он гарантирует, что совпадение будет найдено при любой комбинации форматов. Платой за это является понижение оценки уверенности: если хотя бы одна из дат неоднозначна, оценка снижается с 1.0 до 0.95 или 0.85, что сигнализирует пользователю о необходимости проверки.