modified
This commit is contained in:
@@ -49,7 +49,7 @@ public class SearchController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
public List<String> fetchSuggestions(@RequestParam(value = "q", required = false) String query) {
|
public List<String> fetchSuggestions(@RequestParam(value = "q", required = false) String query) {
|
||||||
log.info("fetch suggests {}",query);
|
log.info("fetch suggests {}",query);
|
||||||
List<String> suggests = searchService.fetchRecentSuggestions(query);
|
List<String> suggests = searchService.fetchSuggestions(query);
|
||||||
log.info("suggests {}",suggests);
|
log.info("suggests {}",suggests);
|
||||||
return suggests;
|
return suggests;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
package io.pratik.elasticsearch.models;
|
package io.pratik.elasticsearch.models;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
import org.springframework.data.elasticsearch.annotations.Field;
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.pratik.elasticsearch.models;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
|
||||||
import org.springframework.data.annotation.Id;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.Field;
|
|
||||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pratik Das
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Document(indexName = "searchsuggest")
|
|
||||||
public class SearchSuggest {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@Field(type = FieldType.Text)
|
|
||||||
private String searchText;
|
|
||||||
|
|
||||||
@CreatedDate
|
|
||||||
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
|
|
||||||
private Instant creationDate;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.pratik.elasticsearch.repositories;
|
|
||||||
|
|
||||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
import io.pratik.elasticsearch.models.SearchSuggest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Pratik Das
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Repository
|
|
||||||
public interface SearchSuggestRepository extends ElasticsearchRepository<SearchSuggest, String> {
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@ import org.elasticsearch.index.query.QueryBuilders;
|
|||||||
import org.elasticsearch.search.aggregations.Aggregation;
|
import org.elasticsearch.search.aggregations.Aggregation;
|
||||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||||
@@ -27,8 +28,6 @@ import org.springframework.data.elasticsearch.core.query.StringQuery;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import io.pratik.elasticsearch.models.Product;
|
import io.pratik.elasticsearch.models.Product;
|
||||||
import io.pratik.elasticsearch.models.SearchSuggest;
|
|
||||||
import io.pratik.elasticsearch.repositories.SearchSuggestRepository;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,16 +38,13 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
public class ProductSearchService {
|
public class ProductSearchService {
|
||||||
|
|
||||||
private static final String PRODUCT_INDEX = "productindex";
|
private static final String PRODUCT_INDEX = "productindex";
|
||||||
private static final String SEARCH_SUGGEST_INDEX = "searchsuggest";
|
|
||||||
|
|
||||||
private ElasticsearchOperations elasticsearchOperations;
|
private ElasticsearchOperations elasticsearchOperations;
|
||||||
private SearchSuggestRepository searchSuggestRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ProductSearchService(final ElasticsearchOperations elasticsearchOperations, final SearchSuggestRepository searchSuggestRepository) {
|
public ProductSearchService(final ElasticsearchOperations elasticsearchOperations) {
|
||||||
super();
|
super();
|
||||||
this.elasticsearchOperations = elasticsearchOperations;
|
this.elasticsearchOperations = elasticsearchOperations;
|
||||||
this.searchSuggestRepository = searchSuggestRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> createProductIndexBulk(final List<Product> products) {
|
public List<String> createProductIndexBulk(final List<Product> products) {
|
||||||
@@ -70,7 +66,7 @@ public class ProductSearchService {
|
|||||||
return documentId;
|
return documentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void findProductCountByBrand(final String brandName) {
|
public void findProductsByBrand(final String brandName) {
|
||||||
QueryBuilder queryBuilder = QueryBuilders
|
QueryBuilder queryBuilder = QueryBuilders
|
||||||
.matchQuery("manufacturer", brandName);
|
.matchQuery("manufacturer", brandName);
|
||||||
// .fuzziness(0.8)
|
// .fuzziness(0.8)
|
||||||
@@ -79,8 +75,6 @@ public class ProductSearchService {
|
|||||||
// .fuzzyTranspositions(true);
|
// .fuzzyTranspositions(true);
|
||||||
|
|
||||||
Query searchQuery = new NativeSearchQueryBuilder()
|
Query searchQuery = new NativeSearchQueryBuilder()
|
||||||
//.addAggregation(AggregationBuilders
|
|
||||||
// .cardinality("category"))
|
|
||||||
.withQuery(queryBuilder)
|
.withQuery(queryBuilder)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -91,18 +85,18 @@ public class ProductSearchService {
|
|||||||
|
|
||||||
log.info("productHits {} {}", productHits.getSearchHits().size(), productHits.getSearchHits());
|
log.info("productHits {} {}", productHits.getSearchHits().size(), productHits.getSearchHits());
|
||||||
|
|
||||||
List<SearchHit<Product>> srchHits =
|
List<SearchHit<Product>> searchHits =
|
||||||
productHits.getSearchHits();
|
productHits.getSearchHits();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (SearchHit<Product> srchHit : srchHits) {
|
for (SearchHit<Product> searchHit : searchHits) {
|
||||||
log.info("srchHit {}", srchHit);
|
log.info("searchHit {}", searchHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void findByProductName(final String productName) {
|
public void findByProductName(final String productName) {
|
||||||
Query searchQuery = new StringQuery(
|
Query searchQuery = new StringQuery(
|
||||||
"{ \"match\": { \"name\": { \"query\": \""+ productName + "\" } } } \"");
|
"{\"match\":{\"name\":{\"query\":\""+ productName + "\"}}}\"");
|
||||||
|
|
||||||
SearchHits<Product> products = elasticsearchOperations.search(searchQuery, Product.class,
|
SearchHits<Product> products = elasticsearchOperations.search(searchQuery, Product.class,
|
||||||
IndexCoordinates.of(PRODUCT_INDEX));
|
IndexCoordinates.of(PRODUCT_INDEX));
|
||||||
@@ -119,10 +113,7 @@ public class ProductSearchService {
|
|||||||
public List<Product> processSearch(final String query) {
|
public List<Product> processSearch(final String query) {
|
||||||
log.info("Search with query {}", query);
|
log.info("Search with query {}", query);
|
||||||
|
|
||||||
// 1. Update searchsuggest Index
|
// 1. Create query on multiple fields enabling fuzzy search
|
||||||
updateSuggestionsIndex(query);
|
|
||||||
|
|
||||||
// 2. Create query on multiple fields enabling fuzzy search
|
|
||||||
QueryBuilder queryBuilder =
|
QueryBuilder queryBuilder =
|
||||||
QueryBuilders
|
QueryBuilders
|
||||||
.multiMatchQuery(query, "name", "description")
|
.multiMatchQuery(query, "name", "description")
|
||||||
@@ -132,13 +123,13 @@ public class ProductSearchService {
|
|||||||
.withFilter(queryBuilder)
|
.withFilter(queryBuilder)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 3. Execute search
|
// 2. Execute search
|
||||||
SearchHits<Product> productHits =
|
SearchHits<Product> productHits =
|
||||||
elasticsearchOperations
|
elasticsearchOperations
|
||||||
.search(searchQuery, Product.class,
|
.search(searchQuery, Product.class,
|
||||||
IndexCoordinates.of(PRODUCT_INDEX));
|
IndexCoordinates.of(PRODUCT_INDEX));
|
||||||
|
|
||||||
// 4. Map searchHits to product list
|
// 3. Map searchHits to product list
|
||||||
List<Product> productMatches = new ArrayList<Product>();
|
List<Product> productMatches = new ArrayList<Product>();
|
||||||
productHits.forEach(srchHit->{
|
productHits.forEach(srchHit->{
|
||||||
productMatches.add(srchHit.getContent());
|
productMatches.add(srchHit.getContent());
|
||||||
@@ -147,32 +138,26 @@ public class ProductSearchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateSuggestionsIndex(String query) {
|
|
||||||
if(query.getBytes().length < 512) {
|
|
||||||
searchSuggestRepository
|
|
||||||
.save(SearchSuggest
|
|
||||||
.builder()
|
|
||||||
.id(query)
|
|
||||||
.searchText(query)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> fetchRecentSuggestions(String query) {
|
public List<String> fetchSuggestions(String query) {
|
||||||
QueryBuilder queryBuilder = QueryBuilders
|
QueryBuilder queryBuilder = QueryBuilders
|
||||||
.wildcardQuery("searchText", query+"*");
|
.wildcardQuery("name", query+"*");
|
||||||
|
|
||||||
Query searchQuery = new NativeSearchQueryBuilder()
|
Query searchQuery = new NativeSearchQueryBuilder()
|
||||||
.withFilter(queryBuilder).build();
|
.withFilter(queryBuilder)
|
||||||
|
.withPageable(PageRequest.of(0, 5))
|
||||||
|
.build();
|
||||||
|
|
||||||
SearchHits<SearchSuggest> searchSuggestions =
|
SearchHits<Product> searchSuggestions =
|
||||||
elasticsearchOperations.search(searchQuery,
|
elasticsearchOperations.search(searchQuery,
|
||||||
SearchSuggest.class,
|
Product.class,
|
||||||
IndexCoordinates.of(SEARCH_SUGGEST_INDEX));
|
IndexCoordinates.of(PRODUCT_INDEX));
|
||||||
|
|
||||||
List<String> suggestions = new ArrayList<String>();
|
List<String> suggestions = new ArrayList<String>();
|
||||||
searchSuggestions.getSearchHits().forEach(srchHit->{
|
|
||||||
suggestions.add(srchHit.getContent().getSearchText());
|
searchSuggestions.getSearchHits().forEach(searchHit->{
|
||||||
|
suggestions.add(searchHit.getContent().getName());
|
||||||
});
|
});
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ class ProductSearchServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link io.pratik.elasticsearch.services.ProductSearchService#findProductCountByBrand(java.lang.String)}.
|
* Test method for {@link io.pratik.elasticsearch.services.ProductSearchService#findProductsByBrand(java.lang.String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testFindProductCountByBrand() {
|
void testFindProductCountByBrand() {
|
||||||
productSearchService.findProductCountByBrand("samsung");
|
productSearchService.findProductsByBrand("samsung");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,14 +165,11 @@ class ProductSearchServiceTest {
|
|||||||
log.info("results {}",results);
|
log.info("results {}",results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSearchIndexUpdate() {
|
|
||||||
productSearchService.updateSuggestionsIndex("samsng 163 cm");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testFetchSearchSuggestions() {
|
void testFetchSearchSuggestions() {
|
||||||
List<String> suggestions = productSearchService.fetchRecentSuggestions("samsng 163 cm");
|
List<String> suggestions = productSearchService.fetchSuggestions("samsng 163 cm");
|
||||||
log.info("suggestions {}",suggestions);
|
log.info("suggestions {}",suggestions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user