У меня есть фрагмент кода, который находит связанные документы и поддокументы из 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());
}
но, к сожалению, не удалось получить желаемый результат, может кто-нибудь посоветовать, как найти наиболее релевантные в под-документах?