Add search engine.
This commit is contained in:
35
src/main/java/org/codiki/core/entities/business/SearchEntity.java
Executable file
35
src/main/java/org/codiki/core/entities/business/SearchEntity.java
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
package org.codiki.core.entities.business;
|
||||||
|
|
||||||
|
import org.codiki.core.entities.persistence.Post;
|
||||||
|
|
||||||
|
public class SearchEntity {
|
||||||
|
|
||||||
|
private Post post;
|
||||||
|
|
||||||
|
private int score;
|
||||||
|
|
||||||
|
public SearchEntity(Post post) {
|
||||||
|
super();
|
||||||
|
this.post = post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Post getPost() {
|
||||||
|
return post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPost(Post post) {
|
||||||
|
this.post = post;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void increaseScore(int pScoreToAdd) {
|
||||||
|
score += pScoreToAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void decreaseScore(int pScoreToRemove) {
|
||||||
|
score -= pScoreToRemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import org.springframework.data.repository.query.Param;
|
|||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface PostRepository extends CrudRepository<Post, Long> {
|
public interface PostRepository extends CrudRepository<Post, Long>, PostSearchRepository {
|
||||||
|
|
||||||
@Query("SELECT p FROM Post p WHERE p.key = :postKey")
|
@Query("SELECT p FROM Post p WHERE p.key = :postKey")
|
||||||
Optional<Post> getByKey(@Param("postKey") final String pPostKey);
|
Optional<Post> getByKey(@Param("postKey") final String pPostKey);
|
||||||
|
|||||||
9
src/main/java/org/codiki/core/repositories/PostSearchRepository.java
Executable file
9
src/main/java/org/codiki/core/repositories/PostSearchRepository.java
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
package org.codiki.core.repositories;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.codiki.core.entities.persistence.Post;
|
||||||
|
|
||||||
|
public interface PostSearchRepository {
|
||||||
|
List<Post> search(final String[] pCriterias);
|
||||||
|
}
|
||||||
51
src/main/java/org/codiki/core/repositories/PostSearchRepositoryImpl.java
Executable file
51
src/main/java/org/codiki/core/repositories/PostSearchRepositoryImpl.java
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
package org.codiki.core.repositories;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.PersistenceContext;
|
||||||
|
import javax.persistence.PersistenceException;
|
||||||
|
import javax.persistence.Query;
|
||||||
|
|
||||||
|
import org.codiki.core.entities.persistence.Post;
|
||||||
|
import org.codiki.core.utils.StringUtils;
|
||||||
|
|
||||||
|
public class PostSearchRepositoryImpl implements PostSearchRepository {
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public List<Post> search(final String[] pCriterias) {
|
||||||
|
List<Post> result = new LinkedList<>();
|
||||||
|
|
||||||
|
final String queryStr = buildSearchQuery(pCriterias);
|
||||||
|
try {
|
||||||
|
final Query query = em.createQuery(queryStr);
|
||||||
|
for(int i = 1 ; i <= pCriterias.length ; i++) {
|
||||||
|
query.setParameter(StringUtils.concat("c", i), StringUtils.concat('%', pCriterias[i - 1].toLowerCase(), '%'));
|
||||||
|
}
|
||||||
|
result = query.getResultList();
|
||||||
|
} catch(final PersistenceException pEx) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String buildSearchQuery(final String[] pCriterias) {
|
||||||
|
final StringBuilder result = new StringBuilder("SELECT p FROM Post p JOIN FETCH p.category JOIN FETCH p.author ");
|
||||||
|
|
||||||
|
for(int i = 1 ; i <= pCriterias.length ; i++) {
|
||||||
|
result.append(StringUtils.concat((i == 1) ? "WHERE" : "OR", " LOWER(p.title) LIKE :c", i,
|
||||||
|
" OR LOWER(p.description) LIKE :c", i,
|
||||||
|
" OR LOWER(p.text) LIKE :c", i,
|
||||||
|
" OR LOWER(p.category.name) LIKE :c", i,
|
||||||
|
" OR LOWER(p.author.name) LIKE :c", i,
|
||||||
|
" OR LOWER(p.author.email) LIKE :c", i, " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,7 +54,9 @@ public class PostController {
|
|||||||
public PostDTO getByKey(@PathVariable("postKey") final String pPostKey,
|
public PostDTO getByKey(@PathVariable("postKey") final String pPostKey,
|
||||||
final HttpServletResponse response) {
|
final HttpServletResponse response) {
|
||||||
final PostDTO result = getByKeyAndSource(pPostKey, response);
|
final PostDTO result = getByKeyAndSource(pPostKey, response);
|
||||||
result.setText(parserService.parse(result.getText()));
|
if(result != null) {
|
||||||
|
result.setText(parserService.parse(result.getText()));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +81,9 @@ public class PostController {
|
|||||||
.map(PostDTO::new).collect(Collectors.toList());
|
.map(PostDTO::new).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/search")
|
@GetMapping("/search/{searchCriteria}")
|
||||||
public List<Post> search() {
|
public List<PostDTO> search(@PathVariable("searchCriteria") final String pSearchCriteria) {
|
||||||
// TODO
|
return postService.search(pSearchCriteria);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/byCategory/{categoryId}")
|
@GetMapping("/byCategory/{categoryId}")
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
package org.codiki.posts;
|
package org.codiki.posts;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.codiki.core.entities.business.SearchEntity;
|
||||||
import org.codiki.core.entities.dto.PostDTO;
|
import org.codiki.core.entities.dto.PostDTO;
|
||||||
import org.codiki.core.entities.persistence.Category;
|
import org.codiki.core.entities.persistence.Category;
|
||||||
import org.codiki.core.entities.persistence.Post;
|
import org.codiki.core.entities.persistence.Post;
|
||||||
@@ -19,6 +25,17 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PostService {
|
public class PostService {
|
||||||
|
private static final int SCORE_TITLE = 50;
|
||||||
|
|
||||||
|
private static final int SCORE_DESCRIPTION = 5;
|
||||||
|
|
||||||
|
private static final int SCORE_TEXT = 1;
|
||||||
|
|
||||||
|
private static final int SCORE_CATEGORY = 30;
|
||||||
|
|
||||||
|
private static final int SCORE_AUTHOR_NAME = 40;
|
||||||
|
|
||||||
|
private static final int SCORE_AUTHOR_EMAIL = 40;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PostRepository postRepository;
|
private PostRepository postRepository;
|
||||||
@@ -96,4 +113,62 @@ public class PostService {
|
|||||||
pResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
|
pResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PostDTO> search(String pSearchCriteria) {
|
||||||
|
final String[] criteriasArray = pSearchCriteria.split(" ");
|
||||||
|
|
||||||
|
final List<SearchEntity> listSearchEntities = new LinkedList<>();
|
||||||
|
postRepository.search(criteriasArray).stream().map(SearchEntity::new).forEach(e -> {
|
||||||
|
calculateScore(e, criteriasArray);
|
||||||
|
listSearchEntities.add(e);
|
||||||
|
});
|
||||||
|
Collections.sort(listSearchEntities, (e1, e2) -> e1.getScore() - e2.getScore());
|
||||||
|
|
||||||
|
return listSearchEntities.stream().map(SearchEntity::getPost).map(PostDTO::new).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateScore(final SearchEntity searchPost, final String[] pCriteriasArray) {
|
||||||
|
for(final String criteria : pCriteriasArray) {
|
||||||
|
calculateScoreForTitle(searchPost, criteria);
|
||||||
|
calculateScoreForDescription(searchPost, criteria);
|
||||||
|
calculateScoreForText(searchPost, criteria);
|
||||||
|
calculateScoreForCategory(searchPost, criteria);
|
||||||
|
calculateScoreForAuthorName(searchPost, criteria);
|
||||||
|
calculateScoreForAuthorEmail(searchPost, criteria);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForTitle(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
if(pSearchPost.getPost().getTitle().contains(pCriteria)) {
|
||||||
|
pSearchPost.increaseScore(SCORE_TITLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForDescription(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
final int criteriaOccurence = StringUtils.countMatches(pSearchPost.getPost().getDescription(), pCriteria);
|
||||||
|
pSearchPost.increaseScore(criteriaOccurence * SCORE_DESCRIPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForText(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
final int criteriaOccurence = StringUtils.countMatches(pSearchPost.getPost().getText(), pCriteria);
|
||||||
|
pSearchPost.increaseScore(criteriaOccurence * SCORE_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForCategory(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
if(pSearchPost.getPost().getCategory().getName().contains(pCriteria)) {
|
||||||
|
pSearchPost.increaseScore(SCORE_CATEGORY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForAuthorName(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
if(pSearchPost.getPost().getAuthor().getName().contains(pCriteria)) {
|
||||||
|
pSearchPost.increaseScore(SCORE_AUTHOR_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateScoreForAuthorEmail(final SearchEntity pSearchPost, final String pCriteria) {
|
||||||
|
if(pSearchPost.getPost().getAuthor().getEmail().contains(pCriteria)) {
|
||||||
|
pSearchPost.increaseScore(SCORE_AUTHOR_EMAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user