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