Skip to content

Commit 8dba91c

Browse files
committed
Merge remote-tracking branch 'stIncMale/main' into JAVA-5729
# Conflicts: # driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java # driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java # driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java # driver-core/src/test/unit/com/mongodb/client/model/search/SearchOperatorTest.java # driver-scala/src/main/scala/org/mongodb/scala/model/search/SearchOperator.scala # driver-scala/src/main/scala/org/mongodb/scala/model/search/package.scala
2 parents e0215d0 + 75cb0e6 commit 8dba91c

File tree

12 files changed

+536
-12
lines changed

12 files changed

+536
-12
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.client.model.search;
17+
18+
import com.mongodb.annotations.Beta;
19+
import com.mongodb.annotations.Reason;
20+
import com.mongodb.annotations.Sealed;
21+
import org.bson.BsonDocument;
22+
23+
/**
24+
* @see SearchOperator#moreLikeThis(BsonDocument)
25+
* @see SearchOperator#moreLikeThis(Iterable)
26+
* @since 4.7
27+
*/
28+
@Sealed
29+
@Beta(Reason.CLIENT)
30+
public interface MoreLikeThisSearchOperator extends SearchOperator {
31+
@Override
32+
TextSearchOperator score(SearchScore modifier);
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.client.model.search;
17+
18+
import com.mongodb.annotations.Beta;
19+
import com.mongodb.annotations.Reason;
20+
import com.mongodb.annotations.Sealed;
21+
22+
/**
23+
* @see SearchOperator#queryString(FieldSearchPath, String)
24+
* @since 5.3
25+
*/
26+
@Sealed
27+
@Beta(Reason.CLIENT)
28+
public interface QueryStringSearchOperator extends SearchOperator {
29+
@Override
30+
QueryStringSearchOperator score(SearchScore modifier);
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.client.model.search;
17+
18+
import com.mongodb.annotations.Beta;
19+
import com.mongodb.annotations.Reason;
20+
import com.mongodb.annotations.Sealed;
21+
22+
/**
23+
* @see SearchOperator#regex(SearchPath, String)
24+
* @see SearchOperator#regex(Iterable, Iterable)
25+
* @since 5.3
26+
*/
27+
28+
@Sealed
29+
@Beta(Reason.CLIENT)
30+
public interface RegexSearchOperator extends SearchOperator {
31+
@Override
32+
RegexSearchOperator score(SearchScore modifier);
33+
}

driver-core/src/main/com/mongodb/client/model/search/SearchConstructibleBsonElement.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
final class SearchConstructibleBsonElement extends AbstractConstructibleBsonElement<SearchConstructibleBsonElement> implements
3232
MustCompoundSearchOperator, MustNotCompoundSearchOperator, ShouldCompoundSearchOperator, FilterCompoundSearchOperator,
3333
ExistsSearchOperator, TextSearchOperator, AutocompleteSearchOperator,
34-
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator, EqualsSearchOperator,
34+
NumberNearSearchOperator, DateNearSearchOperator, GeoNearSearchOperator,
35+
EqualsSearchOperator, MoreLikeThisSearchOperator,
36+
RegexSearchOperator, QueryStringSearchOperator, WildcardSearchOperator,
3537
ValueBoostSearchScore, PathBoostSearchScore, ConstantSearchScore, FunctionSearchScore,
3638
GaussSearchScoreExpression, PathSearchScoreExpression,
3739
FacetSearchCollector,

driver-core/src/main/com/mongodb/client/model/search/SearchOperator.java

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import org.bson.BsonBinary;
2727
import org.bson.BsonNull;
28+
import org.bson.BsonDocument;
2829
import org.bson.BsonType;
2930
import org.bson.Document;
3031
import org.bson.conversions.Bson;
@@ -389,6 +390,48 @@ static EqualsSearchOperator equalsNull(final FieldSearchPath path) {
389390
.append("value", BsonNull.VALUE));
390391
}
391392

393+
/**
394+
* Returns a {@link SearchOperator} that returns documents similar to input document.
395+
*
396+
* @param like The BSON document that is used to extract representative terms to query for.
397+
* @return The requested {@link SearchOperator}.
398+
* @mongodb.atlas.manual atlas-search/morelikethis/ moreLikeThis operator
399+
*/
400+
static MoreLikeThisSearchOperator moreLikeThis(final BsonDocument like) {
401+
return moreLikeThis(singleton(notNull("like", like)));
402+
}
403+
404+
/**
405+
* Returns a {@link SearchOperator} that returns documents similar to input documents.
406+
*
407+
* @param likes The BSON documents that are used to extract representative terms to query for.
408+
* @return The requested {@link SearchOperator}.
409+
* @mongodb.atlas.manual atlas-search/morelikethis/ moreLikeThis operator
410+
*/
411+
static MoreLikeThisSearchOperator moreLikeThis(final Iterable<BsonDocument> likes) {
412+
Iterator<? extends BsonDocument> likesIterator = notNull("likes", likes).iterator();
413+
isTrueArgument("likes must not be empty", likesIterator.hasNext());
414+
BsonDocument firstLike = likesIterator.next();
415+
return new SearchConstructibleBsonElement("moreLikeThis", new Document("like", likesIterator.hasNext() ? likes : firstLike));
416+
}
417+
418+
/**
419+
* Returns a {@link SearchOperator} that supports querying a combination of indexed fields and values.
420+
*
421+
* @param defaultPath The field to be searched by default.
422+
* @param query One or more indexed fields and values to search.
423+
* @return The requested {@link SearchOperator}.
424+
* @mongodb.atlas.manual atlas-search/queryString/ queryString operator
425+
*/
426+
static QueryStringSearchOperator queryString(final FieldSearchPath defaultPath, final String query) {
427+
isTrueArgument("path must not be empty", defaultPath != null);
428+
isTrueArgument("query must not be empty", query != null);
429+
430+
return new SearchConstructibleBsonElement("queryString",
431+
new Document("defaultPath", defaultPath.toBsonValue())
432+
.append("query", query));
433+
}
434+
392435
/**
393436
* Returns a {@link SearchOperator} that performs a search for documents containing an ordered sequence of terms.
394437
*
@@ -419,6 +462,66 @@ static PhraseSearchOperator phrase(final Iterable<? extends SearchPath> paths, f
419462
.append("query", queryIterator.hasNext() ? queries : firstQuery));
420463
}
421464

465+
/**
466+
* Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character.
467+
*
468+
* @param query The string to search for.
469+
* @param path The indexed field to be searched.
470+
* @return The requested {@link SearchOperator}.
471+
* @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator
472+
*/
473+
static WildcardSearchOperator wildcard(final String query, final SearchPath path) {
474+
return wildcard(singleton(notNull("query", query)), singleton(notNull("path", path)));
475+
}
476+
477+
/**
478+
* Returns a {@link SearchOperator} that performs a search using a special characters in the search string that can match any character.
479+
*
480+
* @param queries The non-empty strings to search for.
481+
* @param paths The non-empty index fields to be searched.
482+
* @return The requested {@link SearchOperator}.
483+
* @mongodb.atlas.manual atlas-search/wildcard/ wildcard operator
484+
*/
485+
static WildcardSearchOperator wildcard(final Iterable<String> queries, final Iterable<? extends SearchPath> paths) {
486+
Iterator<String> queryIterator = notNull("queries", queries).iterator();
487+
isTrueArgument("queries must not be empty", queryIterator.hasNext());
488+
String firstQuery = queryIterator.next();
489+
Iterator<? extends SearchPath> pathIterator = notNull("paths", paths).iterator();
490+
isTrueArgument("paths must not be empty", pathIterator.hasNext());
491+
return new SearchConstructibleBsonElement("wildcard", new Document("query", queryIterator.hasNext() ? queries : firstQuery)
492+
.append("path", combineToBsonValue(pathIterator, false)));
493+
}
494+
495+
/**
496+
* Returns a {@link SearchOperator} that performs a search using a regular expression.
497+
*
498+
* @param path The field to be searched.
499+
* @param query The string to search for.
500+
* @return The requested {@link SearchOperator}.
501+
* @mongodb.atlas.manual atlas-search/regex/ regex operator
502+
*/
503+
static RegexSearchOperator regex(final SearchPath path, final String query) {
504+
return regex(singleton(notNull("path", path)), singleton(notNull("query", query)));
505+
}
506+
507+
/**
508+
* Returns a {@link SearchOperator} that performs a search using a regular expression.
509+
*
510+
* @param paths The non-empty fields to be searched.
511+
* @param queries The non-empty strings to search for.
512+
* @return The requested {@link SearchOperator}.
513+
* @mongodb.atlas.manual atlas-search/regex/ regex operator
514+
*/
515+
static RegexSearchOperator regex(final Iterable<? extends SearchPath> paths, final Iterable<String> queries) {
516+
Iterator<? extends SearchPath> pathIterator = notNull("paths", paths).iterator();
517+
isTrueArgument("paths must not be empty", pathIterator.hasNext());
518+
Iterator<String> queryIterator = notNull("queries", queries).iterator();
519+
isTrueArgument("queries must not be empty", queryIterator.hasNext());
520+
String firstQuery = queryIterator.next();
521+
return new SearchConstructibleBsonElement("regex", new Document("path", combineToBsonValue(pathIterator, false))
522+
.append("query", queryIterator.hasNext() ? queries : firstQuery));
523+
}
524+
422525
/**
423526
* Creates a {@link SearchOperator} from a {@link Bson} in situations when there is no builder method that better satisfies your needs.
424527
* This method cannot be used to validate the syntax.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.mongodb.client.model.search;
17+
18+
import com.mongodb.annotations.Beta;
19+
import com.mongodb.annotations.Reason;
20+
import com.mongodb.annotations.Sealed;
21+
22+
/**
23+
* @see SearchOperator#wildcard(String, SearchPath)
24+
* @see SearchOperator#wildcard(Iterable, Iterable)
25+
* @since 4.7
26+
*/
27+
@Sealed
28+
@Beta(Reason.CLIENT)
29+
public interface WildcardSearchOperator extends SearchOperator {
30+
@Override
31+
WildcardSearchOperator score(SearchScore modifier);
32+
}

driver-core/src/main/com/mongodb/internal/connection/DnsMultiServerCluster.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import com.mongodb.connection.ClusterId;
2222
import com.mongodb.connection.ClusterSettings;
2323
import com.mongodb.connection.ClusterType;
24+
import com.mongodb.connection.ServerDescription;
2425
import com.mongodb.lang.Nullable;
2526

2627
import java.util.ArrayList;
2728
import java.util.Collection;
2829
import java.util.Collections;
2930
import java.util.List;
3031
import java.util.concurrent.ThreadLocalRandom;
32+
import java.util.stream.Collectors;
3133

3234
import static com.mongodb.assertions.Assertions.assertNotNull;
3335

@@ -38,7 +40,6 @@ public final class DnsMultiServerCluster extends AbstractMultiServerCluster {
3840
private final DnsSrvRecordMonitor dnsSrvRecordMonitor;
3941
private volatile MongoException srvResolutionException;
4042

41-
4243
public DnsMultiServerCluster(final ClusterId clusterId, final ClusterSettings settings, final ClusterableServerFactory serverFactory,
4344
final DnsSrvRecordMonitorFactory dnsSrvRecordMonitorFactory) {
4445
super(clusterId, settings, serverFactory);
@@ -57,17 +58,33 @@ public void initialize(final Collection<ServerAddress> hosts) {
5758
}
5859
}
5960

60-
private Collection<ServerAddress> applySrvMaxHosts(final Collection<ServerAddress> hosts) {
61-
Collection<ServerAddress> newHosts = hosts;
61+
private Collection<ServerAddress> applySrvMaxHosts(final Collection<ServerAddress> latestSrvHosts) {
6262
Integer srvMaxHosts = getSettings().getSrvMaxHosts();
63-
if (srvMaxHosts != null && srvMaxHosts > 0) {
64-
if (srvMaxHosts < hosts.size()) {
65-
List<ServerAddress> newHostsList = new ArrayList<>(hosts);
66-
Collections.shuffle(newHostsList, ThreadLocalRandom.current());
67-
newHosts = newHostsList.subList(0, srvMaxHosts);
68-
}
63+
if (srvMaxHosts == null || srvMaxHosts <= 0 || latestSrvHosts.size() <= srvMaxHosts) {
64+
return new ArrayList<>(latestSrvHosts);
6965
}
70-
return newHosts;
66+
List<ServerAddress> activeHosts = getActivePriorHosts(latestSrvHosts);
67+
int numNewHostsToAdd = srvMaxHosts - activeHosts.size();
68+
activeHosts.addAll(addShuffledHosts(latestSrvHosts, activeHosts, numNewHostsToAdd));
69+
70+
return activeHosts;
71+
}
72+
73+
private List<ServerAddress> getActivePriorHosts(final Collection<ServerAddress> latestSrvHosts) {
74+
List<ServerAddress> priorHosts = DnsMultiServerCluster.this.getCurrentDescription().getServerDescriptions().stream()
75+
.map(ServerDescription::getAddress).collect(Collectors.toList());
76+
priorHosts.removeIf(host -> !latestSrvHosts.contains(host));
77+
78+
return priorHosts;
79+
}
80+
81+
private List<ServerAddress> addShuffledHosts(final Collection<ServerAddress> latestSrvHosts,
82+
final List<ServerAddress> activePriorHosts, final int numNewHostsToAdd) {
83+
List<ServerAddress> addedHosts = new ArrayList<>(latestSrvHosts);
84+
addedHosts.removeAll(activePriorHosts);
85+
Collections.shuffle(addedHosts, ThreadLocalRandom.current());
86+
87+
return addedHosts.subList(0, numNewHostsToAdd);
7188
}
7289

7390
@Override

driver-core/src/test/functional/com/mongodb/client/model/search/AggregatesSearchIntegrationTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.mongodb.client.model.geojson.Position;
2424
import com.mongodb.client.test.CollectionHelper;
2525
import org.bson.BsonDocument;
26+
import org.bson.BsonString;
2627
import org.bson.codecs.BsonDocumentCodec;
2728
import org.bson.conversions.Bson;
2829
import org.bson.json.JsonWriterSettings;
@@ -81,10 +82,14 @@
8182
import static com.mongodb.client.model.search.SearchOperator.dateRange;
8283
import static com.mongodb.client.model.search.SearchOperator.equalsNull;
8384
import static com.mongodb.client.model.search.SearchOperator.exists;
85+
import static com.mongodb.client.model.search.SearchOperator.moreLikeThis;
8486
import static com.mongodb.client.model.search.SearchOperator.near;
8587
import static com.mongodb.client.model.search.SearchOperator.numberRange;
88+
import static com.mongodb.client.model.search.SearchOperator.queryString;
89+
import static com.mongodb.client.model.search.SearchOperator.regex;
8690
import static com.mongodb.client.model.search.SearchOperator.phrase;
8791
import static com.mongodb.client.model.search.SearchOperator.text;
92+
import static com.mongodb.client.model.search.SearchOperator.wildcard;
8893
import static com.mongodb.client.model.search.SearchOptions.searchOptions;
8994
import static com.mongodb.client.model.search.SearchPath.fieldPath;
9095
import static com.mongodb.client.model.search.SearchPath.wildcardPath;
@@ -612,6 +617,12 @@ private static Stream<Arguments> searchAndSearchMetaArgs() {
612617
near(0, 1.5, fieldPath("fieldName7"), fieldPath("fieldName8")),
613618
near(Instant.ofEpochMilli(1), Duration.ofMillis(3), fieldPath("fieldName9")),
614619
phrase(fieldPath("fieldName10"), "term6"),
620+
regex(fieldPath("title").multi("keyword"), "term7"),
621+
queryString(fieldPath("fieldName12"), "term8"),
622+
moreLikeThis(new BsonDocument("like", new BsonDocument("fieldName10",
623+
new BsonString("term6")))),
624+
wildcard(asList("term10", "term11"), asList(wildcardPath("wildc*rd"), fieldPath("title").multi(
625+
"keyword"))),
615626
SearchOperator.equals(fieldPath("fieldName11"), "term7"),
616627
equalsNull(fieldPath("fieldName12"))
617628
))

0 commit comments

Comments
 (0)