Блум использование алгоритма фильтрации весной загрузки служб


Я реализовал весна загрузки REST-сервис, который имеет только одну функцию - получить статус счетов-фактур по уникальному ID. В рамках этой задачи я реализовал алгоритм фильтра Блума, чтобы избежать ненужных запросов к БД(особенно если мы имеем около 500 миллионов счетов), но я не уверен, что реализовано класс BloomFilterManager лучше от архитектуры и другие чувства. Может, лучше реализовать его в другом месте/путь.

BlomFilterManager.class:

@Component
public class BloomFilterManager {

  private int expectedInsertions=500000000;

  private double ffp=0.01;

  private BloomFilter<String> bloomFilter;

  public BloomFilterManager() {
    this.bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), expectedInsertions, ffp);
  }

  public void populate(List<Invoice> invoices) {
    invoices.stream().map(Invoice::getId).forEach(i -> bloomFilter.put(i));
  }

  public BloomFilter<String> getBloomFilter(){
    return bloomFilter;
  }
}

InvoicesGenerator и bloomfilter населения руководитель:

@Component
public class DataGenerator implements ApplicationRunner {

  @Autowired
  BloomFilterManager bloomFilterManager;

  @Autowired
  InvoiceRepository invoiceRepository;

  @Value("${fake.data.count}")
  private Integer fakeDataCount;

  private List<Invoice> invoices = new ArrayList<>();

  @Override
  public void run(ApplicationArguments args) {

    generateFakeInvoices();
    invoices = invoiceRepository.save(invoices);
    bloomFilterManager.populate(invoices);
  }

  private void generateFakeInvoices() {
    Faker faker = new Faker();
    Invoice.PaymentStatus[] paymentStatuses = Invoice.PaymentStatus.values();

    for (int i = 0; i < fakeDataCount; i++) {

      Invoice invoice = new Invoice(
              faker.number().randomNumber(),
              faker.lorem().word(),
              faker.number().randomDigit(),
              new BigDecimal(Math.random()),
              paymentStatuses[faker.number().numberBetween(0, paymentStatuses.length)],
              faker.date().between(new Date(), DateUtils.addDays(new Date(), 13))
      );
      invoices.add(invoice);
    }
  }
}

Затем я пытаюсь использовать BloomFilterManager в лму услуги:

@Service
public class InvoiceService implements IInvoiceService {

  @Autowired
  private BloomFilterManager bloomFilterManager;

  @Autowired
  private InvoiceRepository invoiceRepository;

  @Override
  public Invoice.PaymentStatus retrievePaymentStatus(String invoiceId) {
    if (!bloomFilterManager.getBloomFilter().mightContain(invoiceId))
      return null;

    return invoiceRepository.findOne(invoiceId).getPaymentStatus();
  }
}

Контроллер:

@RestController
@RequestMapping("/api/invoice")
public class InvoiceController {

  @Autowired
  private InvoiceService invoiceService;

  @GetMapping(path = "/{invoiceId}/status")
  @ResponseStatus(HttpStatus.OK)
  public PaymentStatus retrievePaymentStatus(@PathVariable String invoiceId) {
    PaymentStatus paymentStatus = invoiceService.retrievePaymentStatus(invoiceId);
    if (paymentStatus == null) {
      throw new InvoiceNotFoundException();
    }
    return paymentStatus;
  }
}

Тестовый блок для слоя сервиса:

@RunWith(SpringRunner.class)
@DataJpaTest
public class InvoiceServiceTest {

  @TestConfiguration
  static class InvoiceServiceTestContextConfiguration {
    @Bean
    public InvoiceService invoiceService() {
      return new InvoiceService();
    }

    @Bean
    public BloomFilterManager bloomFilterManager() {
      return new BloomFilterManager();
    }
  }

  @Autowired
  private BloomFilterManager bloomFilterManager;

  @Autowired
  private InvoiceService invoiceService;

  @Autowired
  private InvoiceRepository invoiceRepository;

  @Test
  public void retrievePaymentStatusReturnsPaidStatus() {
    Faker faker = new Faker();

    Invoice invoice = invoiceRepository.save(new Invoice(
            faker.number().randomNumber(),
            faker.lorem().word(),
            faker.number().randomDigit(),
            new BigDecimal(Math.random()),
            Invoice.PaymentStatus.PAID,
            faker.date().between(new Date(), DateUtils.addDays(new Date(), 13))
    ));

    bloomFilterManager.getBloomFilter().put(invoice.getId());

    Invoice.PaymentStatus actualPaymentStatus = invoiceService.retrievePaymentStatus(invoice.getId());

    assertEquals(Invoice.PaymentStatus.PAID, actualPaymentStatus);
  }

  @Test
  public void retrievePaymentStatusReturnsNull() {
    Invoice.PaymentStatus actualPaymentStatus = invoiceService.retrievePaymentStatus("");

    assertEquals(null, actualPaymentStatus);
  }

}

Также я не могу насмехаться над Блум диспетчер фильтров в модульный тест таким образом

when(bloomFilterManager.getBloomFilter().mightContaint(anyString())).therReturn(true);

Любые предложения, что и как я могу улучшить мой код? Лучшие практики или любые другие предложения также приветствуются



180
3
задан 23 февраля 2018 в 02:02 Источник Поделиться
Комментарии