This commit is contained in:
Stefan Hardegger
2025-09-23 13:58:49 +02:00
parent 857871273d
commit 62f017c4ca
6 changed files with 332 additions and 3 deletions

View File

@@ -160,4 +160,71 @@ public class AdminSearchController {
));
}
}
/**
* Migrate to library-aware Solr schema.
* This endpoint handles the migration from non-library-aware to library-aware indexing.
* It clears existing data and reindexes with library context.
*/
@PostMapping("/solr/migrate-library-schema")
public ResponseEntity<Map<String, Object>> migrateLibrarySchema() {
try {
logger.info("Starting Solr library schema migration");
if (!searchServiceAdapter.isSearchServiceAvailable()) {
return ResponseEntity.badRequest().body(Map.of(
"success", false,
"error", "Solr is not available or healthy"
));
}
if (solrService == null) {
return ResponseEntity.badRequest().body(Map.of(
"success", false,
"error", "Solr service not available"
));
}
logger.info("Clearing existing Solr data for library schema migration");
// Note: This assumes the libraryId field has been added to the Solr schema
// Either manually or via schema restart with updated schema files
// Clear existing data that doesn't have libraryId
solrService.recreateIndices();
// Get all data and reindex with library context
List<Story> allStories = storyService.findAllWithAssociations();
List<Author> allAuthors = authorService.findAllWithStories();
logger.info("Reindexing {} stories and {} authors with library context",
allStories.size(), allAuthors.size());
// Bulk index everything (will now include libraryId from current library context)
solrService.bulkIndexStories(allStories);
solrService.bulkIndexAuthors(allAuthors);
int totalIndexed = allStories.size() + allAuthors.size();
logger.info("Solr library schema migration completed successfully");
return ResponseEntity.ok(Map.of(
"success", true,
"message", String.format("Library schema migration completed. Reindexed %d stories and %d authors with library context.",
allStories.size(), allAuthors.size()),
"storiesCount", allStories.size(),
"authorsCount", allAuthors.size(),
"totalCount", totalIndexed,
"note", "Ensure libraryId field exists in Solr schema before running this migration"
));
} catch (Exception e) {
logger.error("Error during Solr library schema migration", e);
return ResponseEntity.internalServerError().body(Map.of(
"success", false,
"error", "Library schema migration failed: " + e.getMessage(),
"details", "Make sure the libraryId field has been added to both stories and authors Solr cores"
));
}
}
}

View File

@@ -15,7 +15,6 @@ import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -50,6 +49,9 @@ public class SolrService {
@Lazy
private ReadingTimeService readingTimeService;
@Autowired
private LibraryService libraryService;
@PostConstruct
public void initializeCores() {
if (!isAvailable()) {
@@ -287,6 +289,12 @@ public class SolrService {
doc.addField("updatedAt", formatDateTime(story.getUpdatedAt()));
doc.addField("dateAdded", formatDateTime(story.getCreatedAt()));
// Add library ID for multi-tenant separation
String currentLibraryId = getCurrentLibraryId();
if (currentLibraryId != null) {
doc.addField("libraryId", currentLibraryId);
}
return doc;
}
@@ -320,6 +328,12 @@ public class SolrService {
doc.addField("createdAt", formatDateTime(author.getCreatedAt()));
doc.addField("updatedAt", formatDateTime(author.getUpdatedAt()));
// Add library ID for multi-tenant separation
String currentLibraryId = getCurrentLibraryId();
if (currentLibraryId != null) {
doc.addField("libraryId", currentLibraryId);
}
return doc;
}
@@ -336,6 +350,20 @@ public class SolrService {
return solrClient != null;
}
/**
* Get current library ID for multi-tenant document separation.
* Falls back to "default" if no library is active.
*/
private String getCurrentLibraryId() {
try {
String libraryId = libraryService.getCurrentLibraryId();
return libraryId != null ? libraryId : "default";
} catch (Exception e) {
logger.warn("Could not get current library ID, using 'default': {}", e.getMessage());
return "default";
}
}
public boolean testConnection() {
if (!isAvailable()) {
return false;
@@ -465,6 +493,10 @@ public class SolrService {
solrQuery.setRows(limit);
// Add library filter for multi-tenant separation
String currentLibraryId = getCurrentLibraryId();
solrQuery.addFilterQuery("libraryId:\"" + escapeQueryChars(currentLibraryId) + "\"");
// Sort by storyCount if available, otherwise by name
solrQuery.setSort("storyCount", SolrQuery.ORDER.desc);
solrQuery.addSort("name", SolrQuery.ORDER.asc);
@@ -496,6 +528,10 @@ public class SolrService {
solrQuery.setFacetMinCount(1);
solrQuery.setFacetLimit(limit);
// Add library filter for multi-tenant separation
String currentLibraryId = getCurrentLibraryId();
solrQuery.addFilterQuery("libraryId:\"" + escapeQueryChars(currentLibraryId) + "\"");
QueryResponse response = solrClient.query(properties.getCores().getStories(), solrQuery);
return response.getFacetField("tagNames_facet").getValues().stream()
@@ -523,6 +559,10 @@ public class SolrService {
solrQuery.setSort("random_" + System.currentTimeMillis(), SolrQuery.ORDER.asc);
}
// Add library filter for multi-tenant separation
String currentLibraryId = getCurrentLibraryId();
solrQuery.addFilterQuery("libraryId:\"" + escapeQueryChars(currentLibraryId) + "\"");
QueryResponse response = solrClient.query(properties.getCores().getStories(), solrQuery);
if (response.getResults().size() > 0) {
@@ -750,6 +790,10 @@ public class SolrService {
List<String> filters = new ArrayList<>();
// Library filter - ensure multi-tenant data separation
String currentLibraryId = getCurrentLibraryId();
filters.add("libraryId:\"" + escapeQueryChars(currentLibraryId) + "\"");
// Tag filters - use facet field for exact matching
if (tags != null && !tags.isEmpty()) {
String tagFilter = tags.stream()