Skip to content

Commit a9bd6dc

Browse files
Merge pull request #262 from aodn/feature/7786-use-double-quote-search
Feature/7786 use double quote search
2 parents bb2555c + 72efbca commit a9bd6dc

2 files changed

Lines changed: 79 additions & 8 deletions

File tree

server/src/main/java/au/org/aodn/ogcapi/server/core/service/ElasticSearch.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,17 +267,35 @@ public ElasticSearchBase.SearchResult<StacCollectionModel> searchByParameters(Li
267267
should = new ArrayList<>();
268268

269269
for (String t : keywords) {
270-
should.add(CQLFields.fuzzy_title.getPropertyEqualToQuery(t));
271-
should.add(CQLFields.fuzzy_desc.getPropertyEqualToQuery(t));
272-
should.add(CQLFields.parameter_vocabs.getPropertyEqualToQuery(t));
273-
should.add(CQLFields.organisation_vocabs.getPropertyEqualToQuery(t));
274-
should.add(CQLFields.platform_vocabs.getPropertyEqualToQuery(t));
275-
should.add(CQLFields.id.getPropertyEqualToQuery(t));
270+
// If user's input (keywords) starts and ends with quote ", and the text is not empty
271+
// treat the user intend to search with the exact term,
272+
// instead of searching in fuzzy fields i.e., fuzzy_title and fuzzy_desc,
273+
// search in the original title and description fields
274+
// other fields are searched with the same term regardless of exact match or not, as they do not use fuzzy matching.
275+
boolean isExact = t.startsWith("\"") && t.endsWith("\"") && t.length() > 2;
276+
// If search text with double quote, remove quotes,
277+
// otherwise keeps same
278+
String term = isExact ? t.substring(1, t.length() - 1) : t;
279+
280+
if (isExact) {
281+
// Match phrase in original title and description, not use fuzzy fields
282+
should.add(CQLFields.title.getPropertyEqualToQuery(term));
283+
should.add(CQLFields.description.getPropertyEqualToQuery(term));
284+
}
285+
else {
286+
should.add(CQLFields.fuzzy_title.getPropertyEqualToQuery(term));
287+
should.add(CQLFields.fuzzy_desc.getPropertyEqualToQuery(term));
288+
}
289+
should.add(CQLFields.parameter_vocabs.getPropertyEqualToQuery(term));
290+
should.add(CQLFields.organisation_vocabs.getPropertyEqualToQuery(term));
291+
should.add(CQLFields.platform_vocabs.getPropertyEqualToQuery(term));
292+
should.add(CQLFields.id.getPropertyEqualToQuery(term));
276293
// A request to not using acronym in title and description in metadata, hence these
277294
// acronym moved to links, for example NRMN record is mentioned in the link title.
278295
// This is a work-around to the requirement but still allow use of NRMN
279-
should.add(CQLFields.links_title_contains.getPropertyEqualToQuery(t));
280-
should.add(CQLFields.credit_contains.getPropertyEqualToQuery(t));
296+
// links_title_contains and credit_contains use match query by default, exact match is not applied here
297+
should.add(CQLFields.links_title_contains.getPropertyEqualToQuery(term));
298+
should.add(CQLFields.credit_contains.getPropertyEqualToQuery(term));
281299
}
282300
}
283301

server/src/test/java/au/org/aodn/ogcapi/server/service/ElasticSearchTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import au.org.aodn.ogcapi.server.core.model.EsFeatureCollectionModel;
55
import au.org.aodn.ogcapi.server.core.model.EsFeatureModel;
66
import au.org.aodn.ogcapi.server.core.model.EsPolygonModel;
7+
import au.org.aodn.ogcapi.server.core.model.enumeration.CQLFields;
78
import au.org.aodn.ogcapi.server.core.model.ogc.FeatureRequest;
89
import au.org.aodn.ogcapi.server.core.service.ElasticSearch;
910
import au.org.aodn.ogcapi.server.core.service.ElasticSearchBase;
@@ -13,6 +14,7 @@
1314
import co.elastic.clients.elasticsearch.core.search.Hit;
1415
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
1516
import co.elastic.clients.elasticsearch.core.search.TotalHits;
17+
import co.elastic.clients.elasticsearch._types.query_dsl.*;
1618
import com.fasterxml.jackson.databind.ObjectMapper;
1719
import org.junit.jupiter.api.BeforeEach;
1820
import org.junit.jupiter.api.Test;
@@ -116,5 +118,56 @@ public void searchFeatureSummaryTest() throws IOException {
116118
featureProps.get("key"));
117119
}
118120

121+
@Test
122+
public void searchByParametersWithDoubleQuote() throws Exception {
123+
String keyword = "\"ocean temperature\"";
124+
List<String> keywords = List.of(keyword);
125+
List<Query> should = new ArrayList<>();
126+
for (String t : keywords) {
127+
boolean isExact = t.startsWith("\"") && t.endsWith("\"") && t.length() > 2;
128+
String term = isExact ? t.substring(1, t.length() - 1) : t;
129+
if (isExact) {
130+
should.add(CQLFields.title.getPropertyEqualToQuery(term));
131+
should.add(CQLFields.description.getPropertyEqualToQuery(term));
132+
} else {
133+
should.add(CQLFields.fuzzy_title.getPropertyEqualToQuery(term));
134+
should.add(CQLFields.fuzzy_desc.getPropertyEqualToQuery(term));
135+
}
136+
should.add(CQLFields.parameter_vocabs.getPropertyEqualToQuery(term));
137+
should.add(CQLFields.organisation_vocabs.getPropertyEqualToQuery(term));
138+
should.add(CQLFields.platform_vocabs.getPropertyEqualToQuery(term));
139+
should.add(CQLFields.id.getPropertyEqualToQuery(term));
140+
should.add(CQLFields.links_title_contains.getPropertyEqualToQuery(term));
141+
should.add(CQLFields.credit_contains.getPropertyEqualToQuery(term));
142+
}
143+
assertEquals(8, should.size(), "Exact match should produce 8 queries (title + description + other fields)");
144+
assertTrue(should.get(0).isMatchPhrase(), "Title query should be MatchPhraseQuery");
145+
assertTrue(should.get(1).isMatchPhrase(), "Description query should be MatchPhraseQuery");
146+
}
119147

148+
@Test
149+
public void searchByParametersWithoutDoubleQuote() throws Exception {
150+
String keyword = "ocean temperature";
151+
List<String> keywords = List.of(keyword);
152+
List<Query> should = new ArrayList<>();
153+
for (String t : keywords) {
154+
boolean isExact = t.startsWith("\"") && t.endsWith("\"") && t.length() > 2;
155+
String term = isExact ? t.substring(1, t.length() - 1) : t;
156+
if (isExact) {
157+
should.add(CQLFields.title.getPropertyEqualToQuery(term));
158+
should.add(CQLFields.description.getPropertyEqualToQuery(term));
159+
} else {
160+
should.add(CQLFields.fuzzy_title.getPropertyEqualToQuery(term));
161+
should.add(CQLFields.fuzzy_desc.getPropertyEqualToQuery(term));
162+
}
163+
should.add(CQLFields.parameter_vocabs.getPropertyEqualToQuery(term));
164+
should.add(CQLFields.organisation_vocabs.getPropertyEqualToQuery(term));
165+
should.add(CQLFields.platform_vocabs.getPropertyEqualToQuery(term));
166+
should.add(CQLFields.id.getPropertyEqualToQuery(term));
167+
should.add(CQLFields.links_title_contains.getPropertyEqualToQuery(term));
168+
should.add(CQLFields.credit_contains.getPropertyEqualToQuery(term));
169+
}
170+
assertEquals(8, should.size(), "Fuzzy match should produce 8 queries");
171+
assertTrue(should.get(0).isMatch(), "fuzzy_title should be MatchQuery");
172+
}
120173
}

0 commit comments

Comments
 (0)