Как оптимизировать сопоставление отпечатков пальцев SourceAFIS для больших списков учащихся?JAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Как оптимизировать сопоставление отпечатков пальцев SourceAFIS для больших списков учащихся?

Сообщение Anonymous »

Я реализовал на Java метод проверки учащихся по отпечаткам пальцев. Этот метод основан на библиотеке SourceAFIS для сопоставления отпечатков пальцев и предназначен для одновременной обработки нескольких отпечатков пальцев. Однако когда количество студентов около 50, время ответа составляет примерно 10 секунд, что слишком медленно для нашего варианта использования.

Подход

  • Асинхронная загрузка расписания и учащихся.
    • Используйте CompletableFuture для одновременной загрузки расписания и связанных с ним учащихся.
  • Пакетная обработка отпечатков пальцев:
    • Извлечение отпечатков пальцев всех учащихся.
    • Разделение отпечатков пальцев на меньшие пакеты в зависимости от количества доступных процессоров.
    • Обрабатывать пакеты параллельно с помощью CompletableFuture и пользовательского пула потоков.
    < /li>
  • Логика сопоставления с использованием SourceAFIS:
    • Используйте классы FingerprintTemplate и FingerprintMatcher из библиотеки SourceAFIS, чтобы сравнить отпечаток зонда с каждым отпечатком пальца в пакете.
    • Определите лучшее совпадение с показателем сходства выше определенного порога.
Уровень обслуживания:

Код: Выделить всё

    @Override
public User verifyStudentFingerprint(Long scheduleId, MultipartFile scannedFingerprintImage) throws IOException {
// Cache the scanned template first to avoid redundant conversions
byte[] scannedFingerprintImageBytes = scannedFingerprintImage.getBytes();
FingerprintTemplate probeTemplate = new FingerprintTemplate(
new FingerprintImage(scannedFingerprintImageBytes)
);

// Fetch schedule and students in parallel using CompletableFuture
CompletableFuture scheduleFuture = CompletableFuture.supplyAsync(() ->
scheduleRepository.findById(scheduleId).orElse(null)
);

CompletableFuture[*]> studentsFuture = scheduleFuture.thenApplyAsync(schedule ->
schedule != null ? scheduleStudentRepository.findByScheduleId(schedule.getId()) : Collections.emptyList()
);

// Wait for both futures to complete
Schedule schedule = scheduleFuture.join();
List students = studentsFuture.join();

if (schedule == null || students.isEmpty()) return null;

// Extract student IDs and fetch fingerprints
List studentIds = students.stream()
.map(s -> s.getStudent().getId())
.collect(Collectors.toList());

// Use batch fetching for fingerprints
List fingerprints = fingerprintRepository.getOneFingerprintPerUser(studentIds);
if (fingerprints.isEmpty()) return null;

// Create a thread pool with the number of available processors
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService executorService = Executors.newFixedThreadPool(processors);

try {
// Process fingerprints in batches
int batchSize = Math.max(1, fingerprints.size() / processors);
List batches = partitionList(fingerprints, batchSize);

// Create tasks for parallel processing
List futures = batches.stream()
.map(batch -> CompletableFuture.supplyAsync(() -> processFingerprintBatch(batch, probeTemplate), executorService))
.toList();

// Find the best match across all batches
Optional bestMatch = futures.stream()
.map(CompletableFuture::join)
.filter(Optional::isPresent)
.map(Optional::get)
.max(Map.Entry.comparingByValue());

if (bestMatch.isEmpty() || bestMatch.get().getValue() < threshold) {
return null;
}

// Update attendance status
Fingerprint matchedFingerprint = bestMatch.get().getKey();
ScheduleStudent matchedStudent = students.stream()
.filter(s ->  s.getStudent().getId().equals(matchedFingerprint.getUser().getId()))
.findFirst()
.orElse(null);

if (matchedStudent != null) {
matchedStudent.setHasLogged(true);
scheduleStudentRepository.save(matchedStudent);
return matchedFingerprint.getUser();
}

return null;
} finally {
executorService.shutdown();
}
}

private  List partitionList(List list, int batchSize) {
if (batchSize  list.subList(
i * batchSize,
Math.min((i + 1) * batchSize, list.size())
))
.collect(Collectors.toList());
}

private Optional processFingerprintBatch(
List batch,
FingerprintTemplate probeTemplate
) {
FingerprintMatcher matcher = new FingerprintMatcher(probeTemplate);

return batch.parallelStream()
.map(fingerprint -> {
FingerprintTemplate template = new FingerprintTemplate(
new FingerprintImage(fingerprint.getFingerprint())
);
return Map.entry(fingerprint, matcher.match(template));
})
.filter(entry -> entry.getValue() >= threshold)
.max(Map.Entry.comparingByValue());
}

Проблема

Метод работает правильно, но слишком медленно. Для 50 студентов обработка занимает около 10 секунд, что влияет на удобство использования. Я считаю, что узким местом может быть:
  • Преобразование изображений отпечатков пальцев в объекты FingerprintTemplate.
  • Процесс сопоставления с использованием FingerprintMatcher. .

Что я пробовал

  • Разделение отпечатков пальцев на пакеты и обработка их параллельно, используя пул потоков.
  • Использование ParallelStream для обработки отпечатков пальцев в каждом пакете.
  • Регулировка размера пакета для снижения накладных расходов.
< h4>Вопросы
  • Существуют ли какие-либо передовые методы оптимизации сопоставления отпечатков пальцев с помощью SourceAFIS, особенно для пакетной обработки?
  • Можно ли? процесс преобразования изображения в шаблон становится узким местом? Если да, то как я могу его оптимизировать?
  • Существуют ли альтернативные подходы или архитектурные изменения, которые могли бы сократить время обработки?

Изменить: дополнительный контекст

  • Я использую SourceAFIS 3.18.1 для Java.
  • Изображения отпечатков пальцев хранятся в базе данных в виде двоичных данных и извлекаются в виде байтов. массивы.


Подробнее здесь: https://stackoverflow.com/questions/793 ... dent-lists
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»