Сравнение неоднозначных дат¶
При оптическом распознавании текста даты извлекаются в виде строк, формат которых не всегда очевиден. Строка 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, что сигнализирует пользователю о необходимости проверки.