Fix Tag Filtering
This commit is contained in:
@@ -206,6 +206,8 @@ public class StoryController {
|
|||||||
@RequestParam(required = false) String sortBy,
|
@RequestParam(required = false) String sortBy,
|
||||||
@RequestParam(required = false) String sortDir) {
|
@RequestParam(required = false) String sortDir) {
|
||||||
|
|
||||||
|
logger.info("CONTROLLER DEBUG: Search request - query='{}', tags={}, authors={}", query, tags, authors);
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -177,6 +177,9 @@ public class TypesenseService {
|
|||||||
try {
|
try {
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
logger.info("SEARCH DEBUG: searchStories called with query='{}', tagFilters={}, authorFilters={}",
|
||||||
|
query, tagFilters, authorFilters);
|
||||||
|
|
||||||
// Convert 0-based page (frontend/backend) to 1-based page (Typesense)
|
// Convert 0-based page (frontend/backend) to 1-based page (Typesense)
|
||||||
int typesensePage = page + 1;
|
int typesensePage = page + 1;
|
||||||
|
|
||||||
@@ -207,9 +210,16 @@ public class TypesenseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tagFilters != null && !tagFilters.isEmpty()) {
|
if (tagFilters != null && !tagFilters.isEmpty()) {
|
||||||
|
logger.info("SEARCH DEBUG: Processing {} tag filters: {}", tagFilters.size(), tagFilters);
|
||||||
String tagFilter = tagFilters.stream()
|
String tagFilter = tagFilters.stream()
|
||||||
.map(tag -> "tagNames:=" + escapeTypesenseValue(tag))
|
.map(tag -> {
|
||||||
|
String escaped = escapeTypesenseValue(tag);
|
||||||
|
String condition = "tagNames:=" + escaped;
|
||||||
|
logger.info("SEARCH DEBUG: Tag '{}' -> escaped '{}' -> condition '{}'", tag, escaped, condition);
|
||||||
|
return condition;
|
||||||
|
})
|
||||||
.collect(Collectors.joining(" || "));
|
.collect(Collectors.joining(" || "));
|
||||||
|
logger.info("SEARCH DEBUG: Final tag filter condition: '{}'", tagFilter);
|
||||||
filterConditions.add("(" + tagFilter + ")");
|
filterConditions.add("(" + tagFilter + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,13 +232,19 @@ public class TypesenseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!filterConditions.isEmpty()) {
|
if (!filterConditions.isEmpty()) {
|
||||||
searchParameters.filterBy(String.join(" && ", filterConditions));
|
String finalFilter = String.join(" && ", filterConditions);
|
||||||
|
logger.info("SEARCH DEBUG: Final filter condition: '{}'", finalFilter);
|
||||||
|
searchParameters.filterBy(finalFilter);
|
||||||
|
} else {
|
||||||
|
logger.info("SEARCH DEBUG: No filter conditions applied");
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchResult searchResult = typesenseClient.collections(STORIES_COLLECTION)
|
SearchResult searchResult = typesenseClient.collections(STORIES_COLLECTION)
|
||||||
.documents()
|
.documents()
|
||||||
.search(searchParameters);
|
.search(searchParameters);
|
||||||
|
|
||||||
|
logger.info("SEARCH DEBUG: Typesense returned {} results", searchResult.getFound());
|
||||||
|
|
||||||
List<StorySearchDto> results = convertSearchResult(searchResult);
|
List<StorySearchDto> results = convertSearchResult(searchResult);
|
||||||
long searchTime = System.currentTimeMillis() - startTime;
|
long searchTime = System.currentTimeMillis() - startTime;
|
||||||
|
|
||||||
@@ -338,7 +354,10 @@ public class TypesenseService {
|
|||||||
List<String> tagNames = story.getTags().stream()
|
List<String> tagNames = story.getTags().stream()
|
||||||
.map(tag -> tag.getName())
|
.map(tag -> tag.getName())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
logger.debug("INDEXING DEBUG: Story '{}' has tags: {}", story.getTitle(), tagNames);
|
||||||
document.put("tagNames", tagNames);
|
document.put("tagNames", tagNames);
|
||||||
|
} else {
|
||||||
|
logger.debug("INDEXING DEBUG: Story '{}' has no tags", story.getTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
document.put("rating", story.getRating() != null ? story.getRating() : 0);
|
document.put("rating", story.getRating() != null ? story.getRating() : 0);
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ interface TagFilterProps {
|
|||||||
export default function TagFilter({ tags, selectedTags, onTagToggle }: TagFilterProps) {
|
export default function TagFilter({ tags, selectedTags, onTagToggle }: TagFilterProps) {
|
||||||
if (!Array.isArray(tags) || tags.length === 0) return null;
|
if (!Array.isArray(tags) || tags.length === 0) return null;
|
||||||
|
|
||||||
// Sort tags by usage count (descending) and then alphabetically
|
// Filter out tags with no stories, then sort by usage count (descending) and then alphabetically
|
||||||
const sortedTags = [...tags].sort((a, b) => {
|
const sortedTags = [...tags]
|
||||||
|
.filter(tag => (tag.storyCount || 0) > 0)
|
||||||
|
.sort((a, b) => {
|
||||||
const aCount = a.storyCount || 0;
|
const aCount = a.storyCount || 0;
|
||||||
const bCount = b.storyCount || 0;
|
const bCount = b.storyCount || 0;
|
||||||
if (bCount !== aCount) {
|
if (bCount !== aCount) {
|
||||||
|
|||||||
@@ -268,7 +268,27 @@ export const searchApi = {
|
|||||||
sortBy?: string;
|
sortBy?: string;
|
||||||
sortDir?: string;
|
sortDir?: string;
|
||||||
}): Promise<SearchResult> => {
|
}): Promise<SearchResult> => {
|
||||||
const response = await api.get('/stories/search', { params });
|
// Create URLSearchParams to properly handle array parameters
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
|
||||||
|
// Add basic parameters
|
||||||
|
searchParams.append('query', params.query);
|
||||||
|
if (params.page !== undefined) searchParams.append('page', params.page.toString());
|
||||||
|
if (params.size !== undefined) searchParams.append('size', params.size.toString());
|
||||||
|
if (params.minRating !== undefined) searchParams.append('minRating', params.minRating.toString());
|
||||||
|
if (params.maxRating !== undefined) searchParams.append('maxRating', params.maxRating.toString());
|
||||||
|
if (params.sortBy) searchParams.append('sortBy', params.sortBy);
|
||||||
|
if (params.sortDir) searchParams.append('sortDir', params.sortDir);
|
||||||
|
|
||||||
|
// Add array parameters - each element gets its own parameter
|
||||||
|
if (params.authors && params.authors.length > 0) {
|
||||||
|
params.authors.forEach(author => searchParams.append('authors', author));
|
||||||
|
}
|
||||||
|
if (params.tags && params.tags.length > 0) {
|
||||||
|
params.tags.forEach(tag => searchParams.append('tags', tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await api.get(`/stories/search?${searchParams.toString()}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user