Skip to content

Commit

Permalink
v28: Add Stemming API (#83)
Browse files Browse the repository at this point in the history
* feat(api): add stemming dictionary management support

- Add `Stemming` class to manage dictionary operations
- Add `StemmingDictionaries` to handle bulk dictionary operations
- Add `StemmingDictionary` to manage individual dictionaries
- Add `StemmingDictionariesRetrieveSchema` for API responses
- Add tests for dictionary creation and retrieval

* ci: update typesense server version to 28.0.rc36
  • Loading branch information
tharropoulos authored Feb 16, 2025
1 parent 0571a01 commit 3b3ffea
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
java: ['8', '11', '17']
services:
typesense:
image: typesense/typesense:27.0
image: typesense/typesense:28.0.rc36
ports:
- 8108:8108/tcp
volumes:
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/typesense/api/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class Client {

private Analytics analytics;

private Stemming stemming;

private Stopwords stopwords;
private Map<String, StopwordsSet> individualStopwordsSets;

Expand All @@ -45,6 +47,7 @@ public Client(Configuration configuration){
this.debug = new Debug(this.apiCall);
this.multiSearch = new MultiSearch(this.apiCall);
this.analytics = new Analytics(this.apiCall);
this.stemming = new Stemming(this.apiCall);
this.stopwords = new Stopwords(this.apiCall);
this.individualStopwordsSets = new HashMap<>();
}
Expand Down Expand Up @@ -100,6 +103,10 @@ public Analytics analytics(){
return this.analytics;
}

public Stemming stemming(){
return this.stemming;
}

public Stopwords stopwords() {
return this.stopwords;
}
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/org/typesense/api/Stemming.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.typesense.api;

import java.util.HashMap;
import java.util.Map;

public class Stemming {
private final ApiCall apiCall;
private final StemmingDictionaries dictionaries;
private final Map<String, StemmingDictionary> individualDictionaries;


public Stemming(ApiCall apiCall) {
this.apiCall = apiCall;
this.dictionaries = new StemmingDictionaries(this.apiCall);
this.individualDictionaries = new HashMap<>();
}

public StemmingDictionaries dictionaries() {
return this.dictionaries;
}

public StemmingDictionary dictionaries(String dictionaryId) {
StemmingDictionary retVal;

if (!this.individualDictionaries.containsKey(dictionaryId)) {
this.individualDictionaries.put(dictionaryId, new StemmingDictionary(dictionaryId, apiCall));
}

retVal = this.individualDictionaries.get(dictionaryId);
return retVal;
}
}
59 changes: 59 additions & 0 deletions src/main/java/org/typesense/api/StemmingDictionaries.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.typesense.api;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.typesense.model.StemmingDictionaryWords;

import com.fasterxml.jackson.databind.ObjectMapper;

public class StemmingDictionaries {
private final ApiCall apiCall;
public final static String RESOURCE_PATH = "/stemming/dictionaries";

public StemmingDictionaries(ApiCall apiCall) {
this.apiCall = apiCall;
}

public String upsert(String dictionaryId, String wordRootCombinations) throws Exception {
Map<String, String> params = Collections.singletonMap("id", dictionaryId);

return this.apiCall.post(this.getEndPoint("import"), wordRootCombinations, params, String.class);
}

public List<StemmingDictionaryWords> upsert(String dictionaryId, List<StemmingDictionaryWords> wordRootCombinations)
throws Exception {
ObjectMapper mapper = new ObjectMapper();
List<String> jsonLines = new ArrayList<>();
List<StemmingDictionaryWords> objectList = new ArrayList<>();

for (StemmingDictionaryWords word : wordRootCombinations) {
jsonLines.add(mapper.writeValueAsString(word));
}

String reqBody = String.join("\n", jsonLines);

Map<String, String> params = Collections.singletonMap("id", dictionaryId);

String resInJsonLineFormat = this.apiCall.post(this.getEndPoint("import"), reqBody, params, String.class);

for (String line : resInJsonLineFormat.split("\n")) {
objectList.add(mapper.readValue(line, StemmingDictionaryWords.class));
}

return objectList;
}

public StemmingDictionariesRetrieveSchema retrieve() throws Exception {
StemmingDictionariesRetrieveSchema response = this.apiCall.get(RESOURCE_PATH, null,
StemmingDictionariesRetrieveSchema.class);
return response != null ? response : new StemmingDictionariesRetrieveSchema();
}

public String getEndPoint(String target) {
return RESOURCE_PATH + "/" + target;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.typesense.api;

import java.util.List;

public class StemmingDictionariesRetrieveSchema {
private List<String> dictionaries;

public List<String> getDictionaries() {
return dictionaries;
}

public void setDictionaries(List<String> dictionaries) {
this.dictionaries = dictionaries;
}
}
23 changes: 23 additions & 0 deletions src/main/java/org/typesense/api/StemmingDictionary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.typesense.api;

import org.typesense.api.utils.URLEncoding;

public class StemmingDictionary {
private final ApiCall apiCall;
private final String dictionaryId;

public StemmingDictionary(String dictionaryId, ApiCall apiCall) {
this.apiCall = apiCall;
this.dictionaryId = dictionaryId;
}


public org.typesense.model.StemmingDictionary retrieve() throws Exception {
return this.apiCall.get(this.getEndpoint(), null, org.typesense.model.StemmingDictionary.class);
}

private String getEndpoint() {
return StemmingDictionaries.RESOURCE_PATH + "/" + URLEncoding.encodeURIComponent(this.dictionaryId);
}

}
11 changes: 11 additions & 0 deletions src/test/java/org/typesense/api/Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.typesense.model.SearchOverrideRule;
import org.typesense.model.SearchOverrideSchema;
import org.typesense.model.SearchSynonymSchema;
import org.typesense.model.StemmingDictionaryWords;
import org.typesense.model.StopwordsSetSchema;
import org.typesense.model.StopwordsSetUpsertSchema;
import org.typesense.model.StopwordsSetsRetrieveAllSchema;
Expand Down Expand Up @@ -140,6 +141,16 @@ public void createTestStopwordsSet() throws Exception {
client.stopwords().upsert("common-words", stopwordsSetSchema);
}


public void createStemmingDictionary() throws Exception{
List<StemmingDictionaryWords> stemmingDictionaryWords = new ArrayList<>();

stemmingDictionaryWords.add(new StemmingDictionaryWords().word("ran").root("run"));
stemmingDictionaryWords.add(new StemmingDictionaryWords().word("running").root("run"));

client.stemming().dictionaries().upsert("irregular-plurals", stemmingDictionaryWords);
}

public void teardown() throws Exception {
CollectionResponse[] collectionResponses = client.collections().retrieve();
for (CollectionResponse c : collectionResponses) {
Expand Down
54 changes: 54 additions & 0 deletions src/test/java/org/typesense/api/StemmingTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.typesense.api;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.typesense.model.StemmingDictionary;
import org.typesense.model.StemmingDictionaryWords;

public class StemmingTest {
private Client client;
private Helper helper;

@BeforeEach
void setUp() throws Exception {
helper = new Helper();
helper.teardown();
client = helper.getClient();
helper.createStemmingDictionary();
}

@Test
void testUpsert() throws Exception {
List<StemmingDictionaryWords> stemmingDictionaryWords = new ArrayList<>();

stemmingDictionaryWords.add(new StemmingDictionaryWords().word("ran").root("run"));
stemmingDictionaryWords.add(new StemmingDictionaryWords().word("running").root("run"));

List<StemmingDictionaryWords> res = client.stemming().dictionaries().upsert("irregular-plurals",
stemmingDictionaryWords);

assertEquals(2, res.size());
assertEquals("ran", res.get(0).getWord());
assertEquals("run", res.get(0).getRoot());
assertEquals("running", res.get(1).getWord());
assertEquals("run", res.get(1).getRoot());
}

@Test
void testRetrieveOne() throws Exception {
StemmingDictionary res = client.stemming().dictionaries("irregular-plurals").retrieve();
assertEquals("irregular-plurals", res.getId());
assertEquals(2, res.getWords().size());
}

@Test
void testRetrieveAll() throws Exception {
StemmingDictionariesRetrieveSchema res = client.stemming().dictionaries().retrieve();
assertEquals(1, res.getDictionaries().size());
assertEquals("irregular-plurals", res.getDictionaries().get(0));
}
}

0 comments on commit 3b3ffea

Please sign in to comment.