mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-10 22:41:02 +00:00
fix(search): expand keyword storage for rebuild safety
This commit is contained in:
parent
cc4782c16d
commit
a7f8b0afcf
4 changed files with 110 additions and 24 deletions
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE skill_search_document
|
||||
ALTER COLUMN keywords TYPE TEXT;
|
||||
|
|
@ -20,7 +20,7 @@ public class SkillSearchDocumentEntity {
|
|||
@Column(name = "namespace_slug", nullable = false, length = 64)
|
||||
private String namespaceSlug;
|
||||
|
||||
@Column(name = "owner_id", nullable = false)
|
||||
@Column(name = "owner_id", nullable = false, length = 128)
|
||||
private String ownerId;
|
||||
|
||||
@Column(length = 256)
|
||||
|
|
@ -38,10 +38,10 @@ public class SkillSearchDocumentEntity {
|
|||
@Column(name = "semantic_vector", columnDefinition = "TEXT")
|
||||
private String semanticVector;
|
||||
|
||||
@Column(nullable = false, length = 20)
|
||||
@Column(nullable = false, length = 32)
|
||||
private String visibility;
|
||||
|
||||
@Column(nullable = false, length = 20)
|
||||
@Column(nullable = false, length = 32)
|
||||
private String status;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ import java.util.Optional;
|
|||
*/
|
||||
@Service
|
||||
public class PostgresFullTextIndexService implements SearchIndexService {
|
||||
private static final int NAMESPACE_SLUG_MAX_LENGTH = 64;
|
||||
private static final int OWNER_ID_MAX_LENGTH = 128;
|
||||
private static final int TITLE_MAX_LENGTH = 256;
|
||||
private static final int VISIBILITY_MAX_LENGTH = 32;
|
||||
private static final int STATUS_MAX_LENGTH = 32;
|
||||
|
||||
private final SkillSearchDocumentJpaRepository repository;
|
||||
private final SearchEmbeddingService searchEmbeddingService;
|
||||
|
|
@ -29,34 +34,35 @@ public class PostgresFullTextIndexService implements SearchIndexService {
|
|||
@Override
|
||||
@Transactional
|
||||
public void index(SkillSearchDocument document) {
|
||||
SkillSearchDocument normalizedDocument = normalize(document);
|
||||
Optional<SkillSearchDocumentEntity> existing = repository.findBySkillId(document.skillId());
|
||||
|
||||
if (existing.isPresent()) {
|
||||
SkillSearchDocumentEntity entity = existing.get();
|
||||
entity.setNamespaceId(document.namespaceId());
|
||||
entity.setNamespaceSlug(document.namespaceSlug());
|
||||
entity.setOwnerId(document.ownerId());
|
||||
entity.setTitle(document.title());
|
||||
entity.setSummary(document.summary());
|
||||
entity.setKeywords(document.keywords());
|
||||
entity.setSearchText(document.searchText());
|
||||
entity.setSemanticVector(buildSemanticVector(document));
|
||||
entity.setVisibility(document.visibility());
|
||||
entity.setStatus(document.status());
|
||||
entity.setNamespaceId(normalizedDocument.namespaceId());
|
||||
entity.setNamespaceSlug(normalizedDocument.namespaceSlug());
|
||||
entity.setOwnerId(normalizedDocument.ownerId());
|
||||
entity.setTitle(normalizedDocument.title());
|
||||
entity.setSummary(normalizedDocument.summary());
|
||||
entity.setKeywords(normalizedDocument.keywords());
|
||||
entity.setSearchText(normalizedDocument.searchText());
|
||||
entity.setSemanticVector(buildSemanticVector(normalizedDocument));
|
||||
entity.setVisibility(normalizedDocument.visibility());
|
||||
entity.setStatus(normalizedDocument.status());
|
||||
repository.save(entity);
|
||||
} else {
|
||||
SkillSearchDocumentEntity entity = new SkillSearchDocumentEntity(
|
||||
document.skillId(),
|
||||
document.namespaceId(),
|
||||
document.namespaceSlug(),
|
||||
document.ownerId(),
|
||||
document.title(),
|
||||
document.summary(),
|
||||
document.keywords(),
|
||||
document.searchText(),
|
||||
buildSemanticVector(document),
|
||||
document.visibility(),
|
||||
document.status()
|
||||
normalizedDocument.skillId(),
|
||||
normalizedDocument.namespaceId(),
|
||||
normalizedDocument.namespaceSlug(),
|
||||
normalizedDocument.ownerId(),
|
||||
normalizedDocument.title(),
|
||||
normalizedDocument.summary(),
|
||||
normalizedDocument.keywords(),
|
||||
normalizedDocument.searchText(),
|
||||
buildSemanticVector(normalizedDocument),
|
||||
normalizedDocument.visibility(),
|
||||
normalizedDocument.status()
|
||||
);
|
||||
repository.save(entity);
|
||||
}
|
||||
|
|
@ -88,4 +94,27 @@ public class PostgresFullTextIndexService implements SearchIndexService {
|
|||
private String safe(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
private SkillSearchDocument normalize(SkillSearchDocument document) {
|
||||
return new SkillSearchDocument(
|
||||
document.skillId(),
|
||||
document.namespaceId(),
|
||||
truncate(document.namespaceSlug(), NAMESPACE_SLUG_MAX_LENGTH),
|
||||
truncate(document.ownerId(), OWNER_ID_MAX_LENGTH),
|
||||
truncate(document.title(), TITLE_MAX_LENGTH),
|
||||
document.summary(),
|
||||
document.keywords(),
|
||||
document.searchText(),
|
||||
document.semanticVector(),
|
||||
truncate(document.visibility(), VISIBILITY_MAX_LENGTH),
|
||||
truncate(document.status(), STATUS_MAX_LENGTH)
|
||||
);
|
||||
}
|
||||
|
||||
private String truncate(String value, int maxLength) {
|
||||
if (value == null || value.length() <= maxLength) {
|
||||
return value;
|
||||
}
|
||||
return value.substring(0, maxLength);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
package com.iflytek.skillhub.search.postgres;
|
||||
|
||||
import com.iflytek.skillhub.infra.jpa.SkillSearchDocumentEntity;
|
||||
import com.iflytek.skillhub.infra.jpa.SkillSearchDocumentJpaRepository;
|
||||
import com.iflytek.skillhub.search.HashingSearchEmbeddingService;
|
||||
import com.iflytek.skillhub.search.SkillSearchDocument;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PostgresFullTextIndexServiceTest {
|
||||
|
||||
@Test
|
||||
void indexShouldTruncateOnlyColumnsThatStillHaveDatabaseLimits() {
|
||||
SkillSearchDocumentJpaRepository repository = mock(SkillSearchDocumentJpaRepository.class);
|
||||
when(repository.findBySkillId(1L)).thenReturn(Optional.empty());
|
||||
|
||||
PostgresFullTextIndexService service = new PostgresFullTextIndexService(
|
||||
repository,
|
||||
new HashingSearchEmbeddingService()
|
||||
);
|
||||
|
||||
SkillSearchDocument document = new SkillSearchDocument(
|
||||
1L,
|
||||
2L,
|
||||
"n".repeat(80),
|
||||
"o".repeat(140),
|
||||
"t".repeat(300),
|
||||
"summary",
|
||||
"k".repeat(700),
|
||||
"search text",
|
||||
null,
|
||||
"PUBLIC",
|
||||
"ACTIVE"
|
||||
);
|
||||
|
||||
service.index(document);
|
||||
|
||||
ArgumentCaptor<SkillSearchDocumentEntity> captor = ArgumentCaptor.forClass(SkillSearchDocumentEntity.class);
|
||||
verify(repository).save(captor.capture());
|
||||
|
||||
SkillSearchDocumentEntity entity = captor.getValue();
|
||||
assertThat(entity.getNamespaceSlug()).hasSize(64);
|
||||
assertThat(entity.getOwnerId()).hasSize(128);
|
||||
assertThat(entity.getTitle()).hasSize(256);
|
||||
assertThat(entity.getKeywords()).hasSize(700);
|
||||
assertThat(entity.getSearchText()).isEqualTo("search text");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue