performance
This commit is contained in:
@@ -14,6 +14,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -270,12 +271,13 @@ public class StoryController {
|
||||
@RequestParam(required = false) Integer minRating,
|
||||
@RequestParam(required = false) Integer maxRating,
|
||||
@RequestParam(required = false) String sortBy,
|
||||
@RequestParam(required = false) String sortDir) {
|
||||
@RequestParam(required = false) String sortDir,
|
||||
@RequestParam(required = false) String facetBy) {
|
||||
|
||||
|
||||
if (typesenseService != null) {
|
||||
SearchResultDto<StorySearchDto> results = typesenseService.searchStories(
|
||||
query, page, size, authors, tags, minRating, maxRating, sortBy, sortDir);
|
||||
query, page, size, authors, tags, minRating, maxRating, sortBy, sortDir, facetBy);
|
||||
return ResponseEntity.ok(results);
|
||||
} else {
|
||||
// Fallback to basic search if Typesense is not available
|
||||
|
||||
@@ -72,7 +72,6 @@ public class TypesenseService {
|
||||
new Field().name("title").type("string").facet(false).sort(true),
|
||||
new Field().name("summary").type("string").facet(false).optional(true),
|
||||
new Field().name("description").type("string").facet(false),
|
||||
new Field().name("contentPlain").type("string").facet(false),
|
||||
new Field().name("authorId").type("string").facet(true),
|
||||
new Field().name("authorName").type("string").facet(true).sort(true),
|
||||
new Field().name("seriesId").type("string").facet(true).optional(true),
|
||||
@@ -82,7 +81,7 @@ public class TypesenseService {
|
||||
new Field().name("wordCount").type("int32").facet(true).sort(true).optional(true),
|
||||
new Field().name("volume").type("int32").facet(true).sort(true).optional(true),
|
||||
new Field().name("createdAt").type("int64").facet(false).sort(true),
|
||||
new Field().name("lastReadAt").type("int64").facet(false).sort(true).optional(true),
|
||||
new Field().name("lastReadAt").type("int64").facet(false).sort(true),
|
||||
new Field().name("sourceUrl").type("string").facet(false).optional(true),
|
||||
new Field().name("coverPath").type("string").facet(false).optional(true)
|
||||
);
|
||||
@@ -206,7 +205,8 @@ public class TypesenseService {
|
||||
Integer minRating,
|
||||
Integer maxRating,
|
||||
String sortBy,
|
||||
String sortDir) {
|
||||
String sortDir,
|
||||
String facetBy) {
|
||||
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
@@ -223,16 +223,19 @@ public class TypesenseService {
|
||||
|
||||
SearchParameters searchParameters = new SearchParameters()
|
||||
.q(normalizedQuery)
|
||||
.queryBy("title,description,contentPlain,authorName,seriesName,tagNames")
|
||||
.queryBy("title,description,authorName,seriesName,tagNames")
|
||||
.page(typesensePage)
|
||||
.perPage(perPage)
|
||||
.highlightFields("title,description")
|
||||
.highlightStartTag("<mark>")
|
||||
.highlightEndTag("</mark>")
|
||||
.facetBy("tagNames,authorName,rating")
|
||||
.maxFacetValues(100)
|
||||
.sortBy(buildSortParameter(normalizedQuery, sortBy, sortDir));
|
||||
|
||||
// Only add facets if requested
|
||||
if (facetBy != null && !facetBy.trim().isEmpty()) {
|
||||
searchParameters.facetBy(facetBy).maxFacetValues(100);
|
||||
}
|
||||
|
||||
logger.debug("Typesense search parameters - facetBy: {}, maxFacetValues: {}",
|
||||
searchParameters.getFacetBy(), searchParameters.getMaxFacetValues());
|
||||
|
||||
@@ -276,7 +279,8 @@ public class TypesenseService {
|
||||
logger.debug("Search result facet counts: {}", searchResult.getFacetCounts());
|
||||
|
||||
List<StorySearchDto> results = convertSearchResult(searchResult);
|
||||
Map<String, List<FacetCountDto>> facets = processFacetCounts(searchResult);
|
||||
Map<String, List<FacetCountDto>> facets = (facetBy != null && !facetBy.trim().isEmpty()) ?
|
||||
processFacetCounts(searchResult) : new HashMap<>();
|
||||
long searchTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
return new SearchResultDto<>(
|
||||
@@ -364,7 +368,7 @@ public class TypesenseService {
|
||||
// First, get the total count of matching stories
|
||||
SearchParameters countParameters = new SearchParameters()
|
||||
.q(normalizedQuery)
|
||||
.queryBy("title,description,contentPlain,authorName,seriesName,tagNames")
|
||||
.queryBy("title,description,authorName,seriesName,tagNames")
|
||||
.perPage(0); // No results, just count
|
||||
|
||||
// Add tag filters if provided
|
||||
@@ -394,7 +398,7 @@ public class TypesenseService {
|
||||
// Now get the actual story at that offset
|
||||
SearchParameters storyParameters = new SearchParameters()
|
||||
.q(normalizedQuery)
|
||||
.queryBy("title,description,contentPlain,authorName,seriesName,tagNames")
|
||||
.queryBy("title,description,authorName,seriesName,tagNames")
|
||||
.page((int) (randomOffset / 250) + 1) // Calculate page (Typesense uses 1-based pages)
|
||||
.perPage(250) // Get multiple results to account for offset within page
|
||||
.sortBy("_text_match:desc,createdAt:desc"); // Use standard sorting
|
||||
@@ -439,7 +443,6 @@ public class TypesenseService {
|
||||
document.put("title", story.getTitle());
|
||||
document.put("summary", story.getSummary() != null ? story.getSummary() : "");
|
||||
document.put("description", story.getDescription() != null ? story.getDescription() : "");
|
||||
document.put("contentPlain", story.getContentPlain() != null ? story.getContentPlain() : "");
|
||||
|
||||
// Author fields - required in schema, use empty string for missing values
|
||||
if (story.getAuthor() != null) {
|
||||
@@ -474,9 +477,9 @@ public class TypesenseService {
|
||||
story.getCreatedAt().toEpochSecond(java.time.ZoneOffset.UTC) :
|
||||
java.time.LocalDateTime.now().toEpochSecond(java.time.ZoneOffset.UTC));
|
||||
|
||||
if (story.getLastReadAt() != null) {
|
||||
document.put("lastReadAt", story.getLastReadAt().toEpochSecond(java.time.ZoneOffset.UTC));
|
||||
}
|
||||
// Always set lastReadAt for consistent sorting - use 0 (epoch) for unread stories
|
||||
document.put("lastReadAt", story.getLastReadAt() != null ?
|
||||
story.getLastReadAt().toEpochSecond(java.time.ZoneOffset.UTC) : 0L);
|
||||
|
||||
if (story.getSourceUrl() != null) {
|
||||
document.put("sourceUrl", story.getSourceUrl());
|
||||
|
||||
Reference in New Issue
Block a user