From 2ae0ae395bf3c71c5627ffb25a0c685aa4d6b9b6 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 16 Dec 2023 17:13:50 +0530 Subject: [PATCH 01/15] add new run command, and updated mysql creds --- Readme.md | 4 +++- src/main/resources/application.properties | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index dd07c08..608bf5a 100644 --- a/Readme.md +++ b/Readme.md @@ -39,7 +39,9 @@ java -jar target/easy-notes-1.0.0.jar Alternatively, you can run the app without packaging it using - ```bash -mvn spring-boot:run +mvn spring-boot:run +or +./mvnw spring-boot:run ``` The app will start running at . diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d357d46..998439f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ ## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) spring.datasource.url = jdbc:mysql://localhost:3306/notes_app?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false spring.datasource.username = root -spring.datasource.password = callicoder +spring.datasource.password = root_1234 ## Hibernate Properties From a8d64c97e1333e23832d3d8a28dd22967d4931cb Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 16 Dec 2023 17:20:41 +0530 Subject: [PATCH 02/15] update readme with wip --- Readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Readme.md b/Readme.md index dd07c08..9edf1fa 100644 --- a/Readme.md +++ b/Readme.md @@ -58,6 +58,11 @@ The app defines following CRUD APIs. DELETE /api/notes/{noteId} +Work in progress + + Text search in notes + GET /api/notes?q=operating%20system + You can test them using postman or any other rest client. ## Learn more From 6edadf9e893b1729561b9f65a5867c9593e8d77f Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 16 Dec 2023 20:34:44 +0530 Subject: [PATCH 03/15] modify api request schema --- Readme.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 70181e6..6165c2b 100644 --- a/Readme.md +++ b/Readme.md @@ -63,7 +63,11 @@ The app defines following CRUD APIs. Work in progress Text search in notes - GET /api/notes?q=operating%20system + GET /api/notes + { + "text" : "Operating System", + "limit" : 10 + } You can test them using postman or any other rest client. From 8d16bf9384a8ce1b9c4e450eaa8269efc6922d6f Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 16 Dec 2023 20:36:23 +0530 Subject: [PATCH 04/15] modify api request schema - 2 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 6165c2b..4b8b2a1 100644 --- a/Readme.md +++ b/Readme.md @@ -63,7 +63,7 @@ The app defines following CRUD APIs. Work in progress Text search in notes - GET /api/notes + GET /api/notes/search { "text" : "Operating System", "limit" : 10 From 2b91cb53d0ee12c7f29432a4192a2e9345f62539 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 16 Dec 2023 23:12:15 +0530 Subject: [PATCH 05/15] brute force implementation of search text --- .../easynotes/controller/NoteController.java | 35 +++++++++++++++-- .../example/easynotes/model/SearchNote.java | 16 ++++++++ .../easynotes/repository/NoteRepository.java | 6 +++ .../example/easynotes/utils/textUtils.java | 39 +++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/example/easynotes/model/SearchNote.java create mode 100644 src/main/java/com/example/easynotes/utils/textUtils.java diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 52f2ef0..e6a25a6 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -2,17 +2,24 @@ import com.example.easynotes.exception.ResourceNotFoundException; import com.example.easynotes.model.Note; +import com.example.easynotes.model.SearchNote; import com.example.easynotes.repository.NoteRepository; +import com.example.easynotes.utils.textUtils; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; + +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; + + + -/** - * Created by rajeevkumarsingh on 27/06/17. - */ @RestController @RequestMapping("/api") public class NoteController { @@ -30,6 +37,27 @@ public Note createNote(@Valid @RequestBody Note note) { return noteRepository.save(note); } + @GetMapping("/notes/search") + public List searchNote(@Valid @RequestBody SearchNote searchNote) { + String text = searchNote.getText(); + List splitTexts = textUtils.splitString(text); + + Integer limit = searchNote.getLimit(); + // System.out.println(splitTexts); + // System.out.println(splitTexts.get(0)); + Set resultantNotes = new HashSet(); + for(int i=0; i currentNotes = noteRepository.getNoteBySearchString(splitTexts.get(i)); + for(int j=0;j resultantListNotes = new ArrayList (resultantNotes); + List finalNotesWithLimit = new ArrayList (); + for(int i=0;i deleteNote(@PathVariable(value = "id") Long noteId) { return ResponseEntity.ok().build(); } + } diff --git a/src/main/java/com/example/easynotes/model/SearchNote.java b/src/main/java/com/example/easynotes/model/SearchNote.java new file mode 100644 index 0000000..45babd0 --- /dev/null +++ b/src/main/java/com/example/easynotes/model/SearchNote.java @@ -0,0 +1,16 @@ +package com.example.easynotes.model; + + + +public class SearchNote { + private String text; + private Integer limit; + + public String getText() { + return text; + } + + public Integer getLimit() { + return limit; + } +} diff --git a/src/main/java/com/example/easynotes/repository/NoteRepository.java b/src/main/java/com/example/easynotes/repository/NoteRepository.java index 4b7b8b3..429a9fa 100644 --- a/src/main/java/com/example/easynotes/repository/NoteRepository.java +++ b/src/main/java/com/example/easynotes/repository/NoteRepository.java @@ -1,7 +1,11 @@ package com.example.easynotes.repository; import com.example.easynotes.model.Note; + +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; /** @@ -10,5 +14,7 @@ @Repository public interface NoteRepository extends JpaRepository { + @Query("select n from Note n where n.title like %?1% or n.content like %?1%") + List getNoteBySearchString(String query); } diff --git a/src/main/java/com/example/easynotes/utils/textUtils.java b/src/main/java/com/example/easynotes/utils/textUtils.java new file mode 100644 index 0000000..a165ee2 --- /dev/null +++ b/src/main/java/com/example/easynotes/utils/textUtils.java @@ -0,0 +1,39 @@ +package com.example.easynotes.utils; +import java.util.ArrayList; +import java.util.List; + +public class textUtils { + private textUtils() { + + } + private static boolean isStringEmpty(String text) { + return text.length() == 0; + } + + private static boolean isStringWhiteSpace(String text) { + return Character.isWhitespace(text.charAt(0)); + } + + public static List splitString(String text) { + List splitStrings = new ArrayList<>(); + String str=""; + + for(int i=0;i<=text.length();i++) { + if(i==text.length()) { + if(!isStringEmpty(str)) { + splitStrings.add(str); + break; + } + } + if(Character.isWhitespace(text.charAt(i))) { + if(!isStringEmpty(str) && !isStringWhiteSpace(str)) { + splitStrings.add(str); + str = ""; + } + } + else str = str + text.charAt(i); + } + return splitStrings; + } + +} From 69bc95058cf43cc5d27452a89b8b895f5c532211 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 30 Dec 2023 09:10:00 +0530 Subject: [PATCH 06/15] add es save option for notes --- .gitignore | 3 + pom.xml | 14 +++- .../easynotes/controller/NoteController.java | 24 +++++- .../com/example/easynotes/model/ESNote.java | 78 +++++++++++++++++++ .../repository/NoteESRepository.java | 16 ++++ .../easynotes/utils/elasticSearch.java | 26 +++++++ .../example/easynotes/utils/esInterface.java | 14 ++++ src/main/resources/application.properties | 8 +- 8 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/example/easynotes/model/ESNote.java create mode 100644 src/main/java/com/example/easynotes/repository/NoteESRepository.java create mode 100644 src/main/java/com/example/easynotes/utils/elasticSearch.java create mode 100644 src/main/java/com/example/easynotes/utils/esInterface.java diff --git a/.gitignore b/.gitignore index ff29930..0091606 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ dist/ nbdist/ .nb-gradle/ .elasticbeanstalk + +### VSCode ### +.vscode/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index baec0d9..969c412 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.5.5 + 2.6.0 @@ -52,6 +52,18 @@ spring-boot-starter-test test + + org.elasticsearch + elasticsearch + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index e6a25a6..40b0f98 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -1,9 +1,11 @@ package com.example.easynotes.controller; import com.example.easynotes.exception.ResourceNotFoundException; +import com.example.easynotes.model.ESNote; import com.example.easynotes.model.Note; import com.example.easynotes.model.SearchNote; import com.example.easynotes.repository.NoteRepository; +import com.example.easynotes.utils.esInterface; import com.example.easynotes.utils.textUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -18,8 +20,6 @@ import java.util.Set; - - @RestController @RequestMapping("/api") public class NoteController { @@ -27,6 +27,9 @@ public class NoteController { @Autowired NoteRepository noteRepository; + @Autowired + esInterface es; + @GetMapping("/notes") public List getAllNotes() { return noteRepository.findAll(); @@ -34,6 +37,8 @@ public List getAllNotes() { @PostMapping("/notes") public Note createNote(@Valid @RequestBody Note note) { + // elasticSearch es = new elasticSearch(); + es.addToES(note); return noteRepository.save(note); } @@ -58,6 +63,21 @@ public List searchNote(@Valid @RequestBody SearchNote searchNote) { return finalNotesWithLimit; } + @GetMapping("/notes/search2") + public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { + String text = searchNote.getText(); + List res = es.getFromES(text); + List ans = new ArrayList(); + for(int i=0;i { + + List findByTitleContainingOrContentContaining(String title, String content); +} + + diff --git a/src/main/java/com/example/easynotes/utils/elasticSearch.java b/src/main/java/com/example/easynotes/utils/elasticSearch.java new file mode 100644 index 0000000..a3f4100 --- /dev/null +++ b/src/main/java/com/example/easynotes/utils/elasticSearch.java @@ -0,0 +1,26 @@ +package com.example.easynotes.utils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.List; +import com.example.easynotes.model.ESNote; +import com.example.easynotes.model.Note; +import com.example.easynotes.repository.NoteESRepository; + +@Service +public class elasticSearch implements esInterface { + @Autowired + private NoteESRepository noteESRepository; + + public void addToES(Note note) { + ESNote esnote = new ESNote(); + // esnote.setId(note.getId()); + esnote.setTitle(note.getTitle()); + esnote.setContent(note.getContent()); + noteESRepository.save(esnote); + } + public List getFromES(String text) { + List res = noteESRepository.findByTitleContainingOrContentContaining(text, text); + return res; + } +} diff --git a/src/main/java/com/example/easynotes/utils/esInterface.java b/src/main/java/com/example/easynotes/utils/esInterface.java new file mode 100644 index 0000000..1568a9d --- /dev/null +++ b/src/main/java/com/example/easynotes/utils/esInterface.java @@ -0,0 +1,14 @@ +package com.example.easynotes.utils; + +import com.example.easynotes.model.Note; + +import java.util.List; + +import com.example.easynotes.model.ESNote; + + +public interface esInterface { + + void addToES(Note note); + List getFromES(String text); +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 998439f..72cd050 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -10,4 +10,10 @@ spring.datasource.password = root_1234 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect # Hibernate ddl auto (create, create-drop, validate, update) -spring.jpa.hibernate.ddl-auto = update \ No newline at end of file +spring.jpa.hibernate.ddl-auto = update + +# Elasticsearch node +spring.data.elasticsearch.cluster-name=elasticsearch +spring.data.elasticsearch.cluster-nodes=localhost:9200 +spring.data.elasticsearch.repositories.enabled=true +spring.main.allow-bean-definition-overriding=true \ No newline at end of file From dc485d20538d5d52a09347d26fac91207e83e61d Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 30 Dec 2023 09:33:57 +0530 Subject: [PATCH 07/15] add created at and updated at, notes id update --- .../easynotes/controller/NoteController.java | 9 ++-- .../com/example/easynotes/model/ESNote.java | 48 +++++++++++-------- .../easynotes/utils/elasticSearch.java | 4 +- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 40b0f98..3af1b06 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -38,8 +38,9 @@ public List getAllNotes() { @PostMapping("/notes") public Note createNote(@Valid @RequestBody Note note) { // elasticSearch es = new elasticSearch(); - es.addToES(note); - return noteRepository.save(note); + Note res = noteRepository.save(note); + es.addToES(res); + return res; } @GetMapping("/notes/search") @@ -70,9 +71,11 @@ public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { List ans = new ArrayList(); for(int i=0;i getFromES(String text) { From 90b6e23da016c59c6380bc54121e1a33460da929 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sat, 30 Dec 2023 09:49:13 +0530 Subject: [PATCH 08/15] support update and delete doc from ES --- .../example/easynotes/controller/NoteController.java | 12 +++++++++++- .../easynotes/repository/NoteESRepository.java | 1 + .../com/example/easynotes/utils/elasticSearch.java | 4 ++++ .../com/example/easynotes/utils/esInterface.java | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 3af1b06..3b05abd 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -96,8 +96,13 @@ public Note updateNote(@PathVariable(value = "id") Long noteId, note.setTitle(noteDetails.getTitle()); note.setContent(noteDetails.getContent()); - + try{ + es.deleteDocFromES(note.getId()); + } catch (Exception e) { + System.out.println("Some error, probably Document missing"); + } Note updatedNote = noteRepository.save(note); + es.addToES(updatedNote); return updatedNote; } @@ -107,6 +112,11 @@ public ResponseEntity deleteNote(@PathVariable(value = "id") Long noteId) { .orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId)); noteRepository.delete(note); + try{ + es.deleteDocFromES(note.getId()); + } catch (Exception e ) { + System.out.println("Some error, probably Document missing"); + } return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/example/easynotes/repository/NoteESRepository.java b/src/main/java/com/example/easynotes/repository/NoteESRepository.java index 221b475..0dda47b 100644 --- a/src/main/java/com/example/easynotes/repository/NoteESRepository.java +++ b/src/main/java/com/example/easynotes/repository/NoteESRepository.java @@ -11,6 +11,7 @@ public interface NoteESRepository extends ElasticsearchRepository { List findByTitleContainingOrContentContaining(String title, String content); + void deleteByNoteId(Long noteId); } diff --git a/src/main/java/com/example/easynotes/utils/elasticSearch.java b/src/main/java/com/example/easynotes/utils/elasticSearch.java index 496a4bf..9982b71 100644 --- a/src/main/java/com/example/easynotes/utils/elasticSearch.java +++ b/src/main/java/com/example/easynotes/utils/elasticSearch.java @@ -25,4 +25,8 @@ public List getFromES(String text) { List res = noteESRepository.findByTitleContainingOrContentContaining(text, text); return res; } + + public void deleteDocFromES(Long noteId) { + noteESRepository.deleteByNoteId(noteId); + } } diff --git a/src/main/java/com/example/easynotes/utils/esInterface.java b/src/main/java/com/example/easynotes/utils/esInterface.java index 1568a9d..b91e960 100644 --- a/src/main/java/com/example/easynotes/utils/esInterface.java +++ b/src/main/java/com/example/easynotes/utils/esInterface.java @@ -11,4 +11,5 @@ public interface esInterface { void addToES(Note note); List getFromES(String text); + void deleteDocFromES(Long noteId); } From 59a492c9260e21ade1f5f4069a962590cdedabae Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sun, 31 Dec 2023 12:07:43 +0530 Subject: [PATCH 09/15] add multiple words search support through es --- .../easynotes/controller/NoteController.java | 25 +++++++++++-------- .../repository/NoteESRepository.java | 1 + .../easynotes/utils/elasticSearch.java | 20 +++++++++++++++ .../example/easynotes/utils/esInterface.java | 1 + 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 3b05abd..9063c8f 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -1,7 +1,6 @@ package com.example.easynotes.controller; import com.example.easynotes.exception.ResourceNotFoundException; -import com.example.easynotes.model.ESNote; import com.example.easynotes.model.Note; import com.example.easynotes.model.SearchNote; import com.example.easynotes.repository.NoteRepository; @@ -64,19 +63,23 @@ public List searchNote(@Valid @RequestBody SearchNote searchNote) { return finalNotesWithLimit; } - @GetMapping("/notes/search2") + @GetMapping("/notes/searches") public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { String text = searchNote.getText(); - List res = es.getFromES(text); + List splitTexts = textUtils.splitString(text); + Integer limit = searchNote.getLimit(); + List finalNoteIds = es.getAllUniqueDocNoteIds(splitTexts); List ans = new ArrayList(); - for(int i=0;i new ResourceNotFoundException("Note", "id", noteId)); + ans.add(curr); + } + catch (Exception e) { + continue; + } } return ans; } diff --git a/src/main/java/com/example/easynotes/repository/NoteESRepository.java b/src/main/java/com/example/easynotes/repository/NoteESRepository.java index 0dda47b..945b26a 100644 --- a/src/main/java/com/example/easynotes/repository/NoteESRepository.java +++ b/src/main/java/com/example/easynotes/repository/NoteESRepository.java @@ -12,6 +12,7 @@ public interface NoteESRepository extends ElasticsearchRepository List findByTitleContainingOrContentContaining(String title, String content); void deleteByNoteId(Long noteId); + List findByTitleContainingOrContentContainingAndNoteIdIsNotNull(String title, String content); } diff --git a/src/main/java/com/example/easynotes/utils/elasticSearch.java b/src/main/java/com/example/easynotes/utils/elasticSearch.java index 9982b71..c8c8026 100644 --- a/src/main/java/com/example/easynotes/utils/elasticSearch.java +++ b/src/main/java/com/example/easynotes/utils/elasticSearch.java @@ -2,7 +2,12 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; + import com.example.easynotes.model.ESNote; import com.example.easynotes.model.Note; import com.example.easynotes.repository.NoteESRepository; @@ -29,4 +34,19 @@ public List getFromES(String text) { public void deleteDocFromES(Long noteId) { noteESRepository.deleteByNoteId(noteId); } + private List getDocNotes(String text){ + List esNoteDocs = noteESRepository.findByTitleContainingOrContentContaining(text, text); + return esNoteDocs; + } + public List getAllUniqueDocNoteIds(List splitTexts) { + Set uniqueNoteIds = new HashSet(); + for(int i=0;i esNoteDocs = getDocNotes(splitTexts.get(i)); + for(ESNote esnote: esNoteDocs) { + if(esnote.getNoteId() != null) uniqueNoteIds.add(esnote.getNoteId()); + } + } + List uniqueNotesIdsList = new ArrayList (uniqueNoteIds); + return uniqueNotesIdsList; + } } diff --git a/src/main/java/com/example/easynotes/utils/esInterface.java b/src/main/java/com/example/easynotes/utils/esInterface.java index b91e960..a2d1b3c 100644 --- a/src/main/java/com/example/easynotes/utils/esInterface.java +++ b/src/main/java/com/example/easynotes/utils/esInterface.java @@ -12,4 +12,5 @@ public interface esInterface { void addToES(Note note); List getFromES(String text); void deleteDocFromES(Long noteId); + List getAllUniqueDocNoteIds(List splitTexts); } From 12d920bae2a93aeb6ac788aa95a4fccfb78d263e Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sun, 31 Dec 2023 12:21:00 +0530 Subject: [PATCH 10/15] logging support at critical flow, note down errors --- .../easynotes/controller/NoteController.java | 13 ++++++++----- .../com/example/easynotes/utils/elasticSearch.java | 11 +++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 9063c8f..64c7981 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -18,6 +18,9 @@ import java.util.List; import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + @RestController @RequestMapping("/api") @@ -29,6 +32,8 @@ public class NoteController { @Autowired esInterface es; + private static final Logger logger = LoggerFactory.getLogger(NoteController.class); + @GetMapping("/notes") public List getAllNotes() { return noteRepository.findAll(); @@ -36,7 +41,6 @@ public List getAllNotes() { @PostMapping("/notes") public Note createNote(@Valid @RequestBody Note note) { - // elasticSearch es = new elasticSearch(); Note res = noteRepository.save(note); es.addToES(res); return res; @@ -48,8 +52,6 @@ public List searchNote(@Valid @RequestBody SearchNote searchNote) { List splitTexts = textUtils.splitString(text); Integer limit = searchNote.getLimit(); - // System.out.println(splitTexts); - // System.out.println(splitTexts.get(0)); Set resultantNotes = new HashSet(); for(int i=0; i currentNotes = noteRepository.getNoteBySearchString(splitTexts.get(i)); @@ -78,6 +80,7 @@ public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { ans.add(curr); } catch (Exception e) { + logger.error("Exception occured while finding Note by id" + e.getMessage()); continue; } } @@ -102,7 +105,7 @@ public Note updateNote(@PathVariable(value = "id") Long noteId, try{ es.deleteDocFromES(note.getId()); } catch (Exception e) { - System.out.println("Some error, probably Document missing"); + logger.error("Exception occured while finding Note by id" + e.getMessage()); } Note updatedNote = noteRepository.save(note); es.addToES(updatedNote); @@ -118,7 +121,7 @@ public ResponseEntity deleteNote(@PathVariable(value = "id") Long noteId) { try{ es.deleteDocFromES(note.getId()); } catch (Exception e ) { - System.out.println("Some error, probably Document missing"); + logger.error("Some error, probably Document missing" + e.getMessage()); } return ResponseEntity.ok().build(); diff --git a/src/main/java/com/example/easynotes/utils/elasticSearch.java b/src/main/java/com/example/easynotes/utils/elasticSearch.java index c8c8026..804d13c 100644 --- a/src/main/java/com/example/easynotes/utils/elasticSearch.java +++ b/src/main/java/com/example/easynotes/utils/elasticSearch.java @@ -12,11 +12,16 @@ import com.example.easynotes.model.Note; import com.example.easynotes.repository.NoteESRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + @Service public class elasticSearch implements esInterface { @Autowired private NoteESRepository noteESRepository; + private static final Logger logger = LoggerFactory.getLogger(elasticSearch.class); + public void addToES(Note note) { ESNote esnote = new ESNote(); esnote.setNoteId(note.getId()); @@ -32,12 +37,17 @@ public List getFromES(String text) { } public void deleteDocFromES(Long noteId) { + logger.info("Deleting " + noteId.toString() + " from ES"); noteESRepository.deleteByNoteId(noteId); } + private List getDocNotes(String text){ + logger.info("Searching " + text + " in ES documents"); List esNoteDocs = noteESRepository.findByTitleContainingOrContentContaining(text, text); + logger.info("Found " + String.format("%d", esNoteDocs.size()) + " matching docs in ES documents"); return esNoteDocs; } + public List getAllUniqueDocNoteIds(List splitTexts) { Set uniqueNoteIds = new HashSet(); for(int i=0;i getAllUniqueDocNoteIds(List splitTexts) { if(esnote.getNoteId() != null) uniqueNoteIds.add(esnote.getNoteId()); } } + logger.info("Found " + String.format("%d", uniqueNoteIds.size()) + " matching docs in ES"); List uniqueNotesIdsList = new ArrayList (uniqueNoteIds); return uniqueNotesIdsList; } From afc050054186d2ffbf90f06972a128e9401705bc Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Sun, 31 Dec 2023 12:24:54 +0530 Subject: [PATCH 11/15] add completed APIs in README --- Readme.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 4b8b2a1..b41837c 100644 --- a/Readme.md +++ b/Readme.md @@ -60,15 +60,19 @@ The app defines following CRUD APIs. DELETE /api/notes/{noteId} -Work in progress - - Text search in notes GET /api/notes/search { "text" : "Operating System", "limit" : 10 } + GET /api/notes/searches + { + "text" : "Operating System fear falling doubts", + "limit" : 10 + } + + You can test them using postman or any other rest client. ## Learn more From 4919f1d47743bbe1906c347f92bf76d03475d69c Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Fri, 12 Jan 2024 16:22:47 +0530 Subject: [PATCH 12/15] add pagination, remove cors error --- pom.xml | 4 +++ .../easynotes/config/SecurityConfig.java | 32 +++++++++++++++++++ .../easynotes/controller/NoteController.java | 24 +++++++++++--- 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/example/easynotes/config/SecurityConfig.java diff --git a/pom.xml b/pom.xml index 969c412..c0a0239 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,10 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-security + org.elasticsearch elasticsearch diff --git a/src/main/java/com/example/easynotes/config/SecurityConfig.java b/src/main/java/com/example/easynotes/config/SecurityConfig.java new file mode 100644 index 0000000..9dbd59d --- /dev/null +++ b/src/main/java/com/example/easynotes/config/SecurityConfig.java @@ -0,0 +1,32 @@ +package com.example.easynotes.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.cors().and().csrf().disable(); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.addAllowedOrigin("*"); // You can replace "*" with specific origins + configuration.addAllowedMethod("*"); + configuration.addAllowedHeader("*"); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 64c7981..39e1046 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +@CrossOrigin(origins = "*", allowedHeaders = "*") @RestController @RequestMapping("/api") public class NoteController { @@ -34,18 +34,30 @@ public class NoteController { private static final Logger logger = LoggerFactory.getLogger(NoteController.class); + @CrossOrigin(origins = "*") @GetMapping("/notes") - public List getAllNotes() { - return noteRepository.findAll(); + public List getAllNotes(@RequestParam(defaultValue="10", name="limit") String limit, + @RequestParam(defaultValue="0", name="offset") String offset) { + List notes = noteRepository.findAll(); + List required_notes = new ArrayList(); + int I_limit = Integer.parseInt(limit); + int I_offset = Integer.parseInt(offset); + + for(int i=I_offset; i searchNote(@Valid @RequestBody SearchNote searchNote) { String text = searchNote.getText(); @@ -65,6 +77,7 @@ public List searchNote(@Valid @RequestBody SearchNote searchNote) { return finalNotesWithLimit; } + @CrossOrigin(origins = "*") @GetMapping("/notes/searches") public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { String text = searchNote.getText(); @@ -87,12 +100,14 @@ public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { return ans; } + @CrossOrigin(origins = "*") @GetMapping("/notes/{id}") public Note getNoteById(@PathVariable(value = "id") Long noteId) { return noteRepository.findById(noteId) .orElseThrow(() -> new ResourceNotFoundException("Note", "id", noteId)); } + @CrossOrigin(origins = "*") @PutMapping("/notes/{id}") public Note updateNote(@PathVariable(value = "id") Long noteId, @Valid @RequestBody Note noteDetails) { @@ -112,6 +127,7 @@ public Note updateNote(@PathVariable(value = "id") Long noteId, return updatedNote; } + @CrossOrigin(origins = "*") @DeleteMapping("/notes/{id}") public ResponseEntity deleteNote(@PathVariable(value = "id") Long noteId) { Note note = noteRepository.findById(noteId) From 3ac0fea4493ba8d491299b21ee43032fd363a741 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Fri, 12 Jan 2024 17:26:27 +0530 Subject: [PATCH 13/15] add offset support search fn --- .../com/example/easynotes/controller/NoteController.java | 3 ++- src/main/java/com/example/easynotes/model/SearchNote.java | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index 39e1046..e2d3efa 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -83,9 +83,10 @@ public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { String text = searchNote.getText(); List splitTexts = textUtils.splitString(text); Integer limit = searchNote.getLimit(); + Integer offset = searchNote.getOffset(); List finalNoteIds = es.getAllUniqueDocNoteIds(splitTexts); List ans = new ArrayList(); - for(int i=0;i Date: Fri, 12 Jan 2024 18:19:07 +0530 Subject: [PATCH 14/15] change get to post method for searches api --- .../java/com/example/easynotes/controller/NoteController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/easynotes/controller/NoteController.java b/src/main/java/com/example/easynotes/controller/NoteController.java index e2d3efa..1eb2742 100644 --- a/src/main/java/com/example/easynotes/controller/NoteController.java +++ b/src/main/java/com/example/easynotes/controller/NoteController.java @@ -78,7 +78,7 @@ public List searchNote(@Valid @RequestBody SearchNote searchNote) { } @CrossOrigin(origins = "*") - @GetMapping("/notes/searches") + @PostMapping("/notes/searches") public List searchNoteES(@Valid @RequestBody SearchNote searchNote) { String text = searchNote.getText(); List splitTexts = textUtils.splitString(text); From d9132d2bd4ad617300d5c6bf5bedbad7ae41e823 Mon Sep 17 00:00:00 2001 From: Saubhik Kumar Date: Fri, 12 Jan 2024 18:47:37 +0530 Subject: [PATCH 15/15] fix empty string error, inf loop error --- .../example/easynotes/utils/textUtils.java | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/easynotes/utils/textUtils.java b/src/main/java/com/example/easynotes/utils/textUtils.java index a165ee2..08d9995 100644 --- a/src/main/java/com/example/easynotes/utils/textUtils.java +++ b/src/main/java/com/example/easynotes/utils/textUtils.java @@ -6,32 +6,23 @@ public class textUtils { private textUtils() { } - private static boolean isStringEmpty(String text) { - return text.length() == 0; - } - - private static boolean isStringWhiteSpace(String text) { - return Character.isWhitespace(text.charAt(0)); - } public static List splitString(String text) { List splitStrings = new ArrayList<>(); - String str=""; - for(int i=0;i<=text.length();i++) { - if(i==text.length()) { - if(!isStringEmpty(str)) { - splitStrings.add(str); - break; - } + int start_ptr = 0; + while(start_ptr < text.length()) { + while(start_ptr < text.length() && Character.isWhitespace(text.charAt(start_ptr))) { + start_ptr += 1; } - if(Character.isWhitespace(text.charAt(i))) { - if(!isStringEmpty(str) && !isStringWhiteSpace(str)) { - splitStrings.add(str); - str = ""; - } + String str=""; + int end_ptr = start_ptr; + while(end_ptr < text.length() && !Character.isWhitespace(text.charAt(end_ptr))) { + str = str + text.charAt(end_ptr); + end_ptr += 1; } - else str = str + text.charAt(i); + if(str.length() > 0) splitStrings.add(str); + start_ptr = end_ptr; } return splitStrings; }