mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-11 22:51:04 +00:00
feat(search): update search documents and query services
This commit is contained in:
parent
d44f9415fe
commit
db0d86ea08
4 changed files with 61 additions and 40 deletions
|
|
@ -3,7 +3,7 @@ package com.iflytek.skillhub.search;
|
|||
import java.util.Set;
|
||||
|
||||
public record SearchVisibilityScope(
|
||||
Long userId,
|
||||
String userId,
|
||||
Set<Long> memberNamespaceIds,
|
||||
Set<Long> adminNamespaceIds
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ public record SkillSearchDocument(
|
|||
Long skillId,
|
||||
Long namespaceId,
|
||||
String namespaceSlug,
|
||||
Long ownerId,
|
||||
String ownerId,
|
||||
String title,
|
||||
String summary,
|
||||
String keywords,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import jakarta.persistence.Query;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class PostgresFullTextQueryService implements SearchQueryService {
|
||||
|
|
@ -20,14 +21,21 @@ public class PostgresFullTextQueryService implements SearchQueryService {
|
|||
|
||||
@Override
|
||||
public SearchResult search(SearchQuery query) {
|
||||
Set<Long> memberNamespaceIds = query.visibilityScope().memberNamespaceIds().isEmpty()
|
||||
? Set.of(-1L)
|
||||
: query.visibilityScope().memberNamespaceIds();
|
||||
Set<Long> adminNamespaceIds = query.visibilityScope().adminNamespaceIds().isEmpty()
|
||||
? Set.of(-1L)
|
||||
: query.visibilityScope().adminNamespaceIds();
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT skill_id FROM skill_search_document WHERE 1=1 ");
|
||||
|
||||
// Visibility filtering
|
||||
sql.append("AND (visibility = 'PUBLIC' ");
|
||||
if (query.visibilityScope().userId() != null) {
|
||||
sql.append("OR (visibility = 'NAMESPACE' AND namespace_id IN :memberNamespaceIds) ");
|
||||
sql.append("OR (visibility = 'PRIVATE' AND namespace_id IN :adminNamespaceIds) ");
|
||||
sql.append("OR (visibility = 'NAMESPACE_ONLY' AND namespace_id IN :memberNamespaceIds) ");
|
||||
sql.append("OR (visibility = 'PRIVATE' AND (namespace_id IN :adminNamespaceIds OR owner_id = :userId)) ");
|
||||
}
|
||||
sql.append(") ");
|
||||
|
||||
|
|
@ -41,16 +49,18 @@ public class PostgresFullTextQueryService implements SearchQueryService {
|
|||
|
||||
// Full-text search
|
||||
if (query.keyword() != null && !query.keyword().isBlank()) {
|
||||
sql.append("AND to_tsvector('english', search_text) @@ plainto_tsquery('english', :keyword) ");
|
||||
sql.append("AND search_vector @@ plainto_tsquery('simple', :keyword) ");
|
||||
}
|
||||
|
||||
// Sorting
|
||||
if ("downloads".equals(query.sortBy())) {
|
||||
sql.append("ORDER BY (SELECT download_count FROM skill WHERE id = skill_id) DESC ");
|
||||
} else if ("rating".equals(query.sortBy())) {
|
||||
sql.append("ORDER BY (SELECT rating_avg FROM skill WHERE id = skill_id) DESC ");
|
||||
} else if ("newest".equals(query.sortBy())) {
|
||||
sql.append("ORDER BY (SELECT created_at FROM skill WHERE id = skill_id) DESC ");
|
||||
sql.append("ORDER BY (SELECT updated_at FROM skill WHERE id = skill_id) DESC ");
|
||||
} else if ("relevance".equals(query.sortBy()) && query.keyword() != null && !query.keyword().isBlank()) {
|
||||
sql.append("ORDER BY ts_rank(to_tsvector('english', search_text), plainto_tsquery('english', :keyword)) DESC ");
|
||||
sql.append("ORDER BY ts_rank(search_vector, plainto_tsquery('simple', :keyword)) DESC ");
|
||||
} else {
|
||||
sql.append("ORDER BY updated_at DESC ");
|
||||
}
|
||||
|
|
@ -61,8 +71,9 @@ public class PostgresFullTextQueryService implements SearchQueryService {
|
|||
Query nativeQuery = entityManager.createNativeQuery(sql.toString());
|
||||
|
||||
if (query.visibilityScope().userId() != null) {
|
||||
nativeQuery.setParameter("memberNamespaceIds", query.visibilityScope().memberNamespaceIds());
|
||||
nativeQuery.setParameter("adminNamespaceIds", query.visibilityScope().adminNamespaceIds());
|
||||
nativeQuery.setParameter("memberNamespaceIds", memberNamespaceIds);
|
||||
nativeQuery.setParameter("adminNamespaceIds", adminNamespaceIds);
|
||||
nativeQuery.setParameter("userId", query.visibilityScope().userId());
|
||||
}
|
||||
|
||||
if (query.namespaceId() != null) {
|
||||
|
|
@ -83,14 +94,21 @@ public class PostgresFullTextQueryService implements SearchQueryService {
|
|||
|
||||
// Count total
|
||||
String countSql = sql.toString().replaceFirst("SELECT skill_id", "SELECT COUNT(*)");
|
||||
countSql = countSql.substring(0, countSql.indexOf("ORDER BY"));
|
||||
countSql = countSql.substring(0, countSql.indexOf("LIMIT"));
|
||||
int orderByIndex = countSql.indexOf("ORDER BY");
|
||||
if (orderByIndex >= 0) {
|
||||
countSql = countSql.substring(0, orderByIndex);
|
||||
}
|
||||
int limitIndex = countSql.indexOf("LIMIT");
|
||||
if (limitIndex >= 0) {
|
||||
countSql = countSql.substring(0, limitIndex);
|
||||
}
|
||||
|
||||
Query countQuery = entityManager.createNativeQuery(countSql);
|
||||
|
||||
if (query.visibilityScope().userId() != null) {
|
||||
countQuery.setParameter("memberNamespaceIds", query.visibilityScope().memberNamespaceIds());
|
||||
countQuery.setParameter("adminNamespaceIds", query.visibilityScope().adminNamespaceIds());
|
||||
countQuery.setParameter("memberNamespaceIds", memberNamespaceIds);
|
||||
countQuery.setParameter("adminNamespaceIds", adminNamespaceIds);
|
||||
countQuery.setParameter("userId", query.visibilityScope().userId());
|
||||
}
|
||||
|
||||
if (query.namespaceId() != null) {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,12 @@ public class PostgresSearchRebuildService implements SearchRebuildService {
|
|||
|
||||
@Override
|
||||
public void rebuildAll() {
|
||||
// This would need a findAll method in SkillRepository
|
||||
// For now, we'll leave it as a placeholder
|
||||
throw new UnsupportedOperationException("rebuildAll not yet implemented");
|
||||
List<SkillSearchDocument> documents = skillRepository.findAll().stream()
|
||||
.filter(skill -> skill.getStatus() == SkillStatus.ACTIVE)
|
||||
.map(this::toDocument)
|
||||
.flatMap(Optional::stream)
|
||||
.toList();
|
||||
searchIndexService.batchIndex(documents);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -52,30 +55,7 @@ public class PostgresSearchRebuildService implements SearchRebuildService {
|
|||
return;
|
||||
}
|
||||
|
||||
Skill skill = skillOpt.get();
|
||||
Optional<Namespace> namespaceOpt = namespaceRepository.findById(skill.getNamespaceId());
|
||||
if (namespaceOpt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Namespace namespace = namespaceOpt.get();
|
||||
|
||||
String searchText = buildSearchText(skill);
|
||||
|
||||
SkillSearchDocument document = new SkillSearchDocument(
|
||||
skill.getId(),
|
||||
skill.getNamespaceId(),
|
||||
namespace.getSlug(),
|
||||
skill.getOwnerId(),
|
||||
skill.getDisplayName() != null ? skill.getDisplayName() : skill.getSlug(),
|
||||
skill.getSummary(),
|
||||
"", // keywords - could be extracted from metadata
|
||||
searchText,
|
||||
skill.getVisibility().name(),
|
||||
skill.getStatus().name()
|
||||
);
|
||||
|
||||
searchIndexService.index(document);
|
||||
toDocument(skillOpt.get()).ifPresent(searchIndexService::index);
|
||||
}
|
||||
|
||||
private String buildSearchText(Skill skill) {
|
||||
|
|
@ -89,4 +69,27 @@ public class PostgresSearchRebuildService implements SearchRebuildService {
|
|||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
|
||||
private Optional<SkillSearchDocument> toDocument(Skill skill) {
|
||||
Optional<Namespace> namespaceOpt = namespaceRepository.findById(skill.getNamespaceId());
|
||||
if (namespaceOpt.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Namespace namespace = namespaceOpt.get();
|
||||
String searchText = buildSearchText(skill);
|
||||
|
||||
return Optional.of(new SkillSearchDocument(
|
||||
skill.getId(),
|
||||
skill.getNamespaceId(),
|
||||
namespace.getSlug(),
|
||||
skill.getOwnerId(),
|
||||
skill.getDisplayName() != null ? skill.getDisplayName() : skill.getSlug(),
|
||||
skill.getSummary(),
|
||||
"",
|
||||
searchText,
|
||||
skill.getVisibility().name(),
|
||||
skill.getStatus().name()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue