Весенние рамки mongodb найти наиболее подходящие документы к югу - PullRequest
0 голосов
/ 19 июня 2019

У меня есть фрагмент кода, который находит связанные документы и поддокументы из mongodb с использованием критериев, мой код работает нормально, но теперь я хочу отсортировать результаты по верхнему совпадению по минимальному соответствию, например, у меня есть следующие документы:

{"_id":{"_id":"48999"},"availableOnTV":true,"subType":"SHOW","type":"PROGRAM","titles":[{"language":"AR","title":"test"}],"descriptions":[{"language":"AR","shortDescription":"..."}],"url":{},"image":{"thumbnailImage":"....jpg"},"categoryIds":[{"_id":"7908"},{"_id":"7892"},{"_id":"7883"},{"_id":"7860"}],"personIds":[{"_id":"2411"}],"date":{"productionDate":"2001-01-01T00:00:00.000Z","sortDate":"2019-01-01T00:00:00.000Z","creationDate":"2013-11-03T05:30:00.000Z","modificationDate":"2018-02-14T16:56:38.000Z"},"pricingPlans":[{"_id":{"_id":"8881"},"date":{"startDate":"2013-11-02T05:30:00.000Z","endDate":"2067-01-01T00:00:00.000Z"},"type":"BROWSE_ONLY"}],"advertisementZone":{"advertisementZone":""},"_class":"Program"}

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

Вот мой код, который делает это:

public Optional<ProductList> getRelated(String id, Set<String> pricingPlanIds, Pageable pageable)
        throws GenericException {
    Optional<ProductList> productList = this.getById(id, pricingPlanIds);
    if (!productList.isPresent()) {
        return Optional.empty();
    }

    Optional<ProductList> products = Optional.empty();

    for (Product product : productList.get().getProducts()) {
        Criteria buildExact = buildExact(product);
        Criteria buildSimilar = buildSimilar(product);
        Criteria buildLessSimilar = buildLessSimilar(product);

        Criteria productTypeCriteria = Criteria.where(RelatedParam.PRODUCT_TYPE.getParam())
                .is(product.getType().name());

        Criteria identicalProductCriteria = Criteria.where(RelatedParam.PRODUCT_ID.getParam())
                .ne(product.getId().getId());

        Criteria pricingPlanCriteria = new Criteria();
        pricingPlanCriteria = Criteria.where(RelatedParam.PRICING_PLAN_IDS.getParam()).in(pricingPlanIds);

        Criteria query = new Criteria();
        query.andOperator(productTypeCriteria, identicalProductCriteria, pricingPlanCriteria);
        query.orOperator(buildExact, buildSimilar, buildLessSimilar);



        products = aggregator.getRelated(pageable, query.getCriteriaObject());

        products.get().getProducts().stream().forEach(p -> System.out.println(p.getId().getId() + " " + p.getTitles()));
    }

    return products;
}

private Criteria buildLessSimilar(Product product) {
    Criteria criteria = new Criteria();
    if (product.getPersonIds() != null && !product.getPersonIds().isEmpty()) {
        criteria = Criteria.where(RelatedParam.PERSON.getParam())
                .in(product.getPersonIds().stream().map(p -> p.getId()).collect(Collectors.toList()));
    }

    return criteria;
}

private Criteria buildExact(Product product) {
    Criteria criteria = new Criteria();
    List<Criteria> criterias = new ArrayList<>();

    if (product.getPersonIds() != null && !product.getPersonIds().isEmpty()) {
        Criteria personsIdsCategories = Criteria.where(RelatedParam.PERSON.getParam())
                .in(product.getPersonIds().stream().map(p -> p.getId()).collect(Collectors.toList()));

        System.out.println(personsIdsCategories.getCriteriaObject());
        criterias.add(personsIdsCategories);
    }

    if (product.getCategoryIds() != null && !product.getCategoryIds().isEmpty()) {
        Criteria categoriesIdsCriteria = Criteria.where(RelatedParam.CATEGORY.getParam())
                .in(product.getCategoryIds().stream().map(c -> c.getId()).collect(Collectors.toList()));
        criterias.add(categoriesIdsCriteria);
    }

    if (product.getDate().getProductionDate() != null) { 
        LocalDate fromProductionDate = getProductionDate(product.getDate().getProductionDate());
        LocalDate toProductionDate = fromProductionDate.plusYears(1);
        Criteria productionDateCriteria = Criteria.where(RelatedParam.PRODUCTION_DATE.getParam()).gte(fromProductionDate).lt(toProductionDate);
        criterias.add(productionDateCriteria);
    }


    criteria.andOperator(criterias.toArray(new Criteria[criterias.size()]));



    return criteria;
}

private LocalDate getProductionDate(Date productionDate) {
    int year = productionDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getYear();
    return LocalDate.of(year, 01, 01);
}

private Criteria buildSimilar(Product product) {
    Criteria criteria = new Criteria();
    List<Criteria> criterias = new ArrayList<>();

    if (product.getPersonIds() != null && !product.getPersonIds().isEmpty()) {
        Criteria personsIdsCategories = Criteria.where(RelatedParam.PERSON.getParam())
                .in(product.getPersonIds().stream().map(p -> p.getId()).collect(Collectors.toList()));
        criterias.add(personsIdsCategories);
    }

    if (product.getCategoryIds() != null && !product.getCategoryIds().isEmpty()) {
        Criteria categoriesIdsCriteria = Criteria.where(RelatedParam.CATEGORY.getParam())
                .in(product.getCategoryIds().stream().map(c -> c.getId()).collect(Collectors.toList()));
        criterias.add(categoriesIdsCriteria);
    }

    if (product.getDate().getProductionDate() != null) {
        LocalDate fromProductionDate = getProductionDate(product.getDate().getProductionDate());
        LocalDate toProductionDate = fromProductionDate.plusYears(1);
        Criteria productionDateCriteria = Criteria.where(RelatedParam.PRODUCTION_DATE.getParam()).gte(fromProductionDate).lt(toProductionDate);
        criterias.add(productionDateCriteria);
    }

    criteria.orOperator(criterias.toArray(new Criteria[criterias.size()]));
    return criteria;
}

и вот что я пытался достичь желаемого результата, но только с жестко закодированными значениями согласно следующему результату поиска: Сортировка по релевантности с MongoDB

    AggregateIterable<Document> output = collection.aggregate(Arrays.asList(
            new Document("$match", cat),
            new Document("$match", per),
            new Document("$match", type),
            new Document("$unwind", "$categoryIds"),
            new Document("$match", cat),
            new Document("$match", per),
            new Document("$match", type)
            ));

    for (Document dbObject : output) {
        System.out.println(dbObject.toJson());
    }

но, к сожалению, не удалось получить желаемый результат, может кто-нибудь посоветовать, как найти наиболее релевантные в под-документах?

...