replacing opensearch with solr

This commit is contained in:
Stefan Hardegger
2025-09-22 09:44:50 +02:00
parent 9e684a956b
commit 87f37567fb
40 changed files with 2000 additions and 3464 deletions

View File

@@ -69,11 +69,11 @@ export default function LibraryContent() {
}, []);
const convertFacetsToTags = (facets?: Record<string, FacetCount[]>): Tag[] => {
if (!facets || !facets.tagNames) {
if (!facets || !facets.tagNames_facet) {
return [];
}
return facets.tagNames.map(facet => {
return facets.tagNames_facet.map(facet => {
// Find the full tag data by name
const fullTag = fullTags.find(tag => tag.name.toLowerCase() === facet.value.toLowerCase());

View File

@@ -493,11 +493,11 @@ async function processIndividualMode(
console.log(`Bulk import completed: ${importedCount} imported, ${skippedCount} skipped, ${errorCount} errors`);
// Trigger OpenSearch reindex if any stories were imported
// Trigger Solr reindex if any stories were imported
if (importedCount > 0) {
try {
console.log('Triggering OpenSearch reindex after bulk import...');
const reindexUrl = `http://backend:8080/api/admin/search/opensearch/reindex`;
console.log('Triggering Solr reindex after bulk import...');
const reindexUrl = `http://backend:8080/api/admin/search/solr/reindex`;
const reindexResponse = await fetch(reindexUrl, {
method: 'POST',
headers: {
@@ -508,12 +508,12 @@ async function processIndividualMode(
if (reindexResponse.ok) {
const reindexResult = await reindexResponse.json();
console.log('OpenSearch reindex completed:', reindexResult);
console.log('Solr reindex completed:', reindexResult);
} else {
console.warn('OpenSearch reindex failed:', reindexResponse.status);
console.warn('Solr reindex failed:', reindexResponse.status);
}
} catch (error) {
console.warn('Failed to trigger OpenSearch reindex:', error);
console.warn('Failed to trigger Solr reindex:', error);
// Don't fail the whole request if reindex fails
}
}

View File

@@ -11,18 +11,18 @@ interface SystemSettingsProps {
export default function SystemSettings({}: SystemSettingsProps) {
const [searchEngineStatus, setSearchEngineStatus] = useState<{
currentEngine: string;
openSearchAvailable: boolean;
solrAvailable: boolean;
loading: boolean;
message: string;
success?: boolean;
}>({
currentEngine: 'opensearch',
openSearchAvailable: false,
currentEngine: 'solr',
solrAvailable: false,
loading: false,
message: ''
});
const [openSearchStatus, setOpenSearchStatus] = useState<{
const [solrStatus, setSolrStatus] = useState<{
reindex: { loading: boolean; message: string; success?: boolean };
recreate: { loading: boolean; message: string; success?: boolean };
}>({
@@ -312,7 +312,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
setSearchEngineStatus(prev => ({
...prev,
currentEngine: status.primaryEngine,
openSearchAvailable: status.openSearchAvailable,
solrAvailable: status.solrAvailable,
}));
} catch (error: any) {
console.error('Failed to load search engine status:', error);
@@ -321,16 +321,16 @@ export default function SystemSettings({}: SystemSettingsProps) {
const handleOpenSearchReindex = async () => {
setOpenSearchStatus(prev => ({
const handleSolrReindex = async () => {
setSolrStatus(prev => ({
...prev,
reindex: { loading: true, message: 'Reindexing OpenSearch...', success: undefined }
reindex: { loading: true, message: 'Reindexing Solr...', success: undefined }
}));
try {
const result = await searchAdminApi.reindexOpenSearch();
const result = await searchAdminApi.reindexSolr();
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
reindex: {
loading: false,
@@ -340,13 +340,13 @@ export default function SystemSettings({}: SystemSettingsProps) {
}));
setTimeout(() => {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
reindex: { loading: false, message: '', success: undefined }
}));
}, 8000);
} catch (error: any) {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
reindex: {
loading: false,
@@ -356,7 +356,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
}));
setTimeout(() => {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
reindex: { loading: false, message: '', success: undefined }
}));
@@ -364,16 +364,16 @@ export default function SystemSettings({}: SystemSettingsProps) {
}
};
const handleOpenSearchRecreate = async () => {
setOpenSearchStatus(prev => ({
const handleSolrRecreate = async () => {
setSolrStatus(prev => ({
...prev,
recreate: { loading: true, message: 'Recreating OpenSearch indices...', success: undefined }
recreate: { loading: true, message: 'Recreating Solr indices...', success: undefined }
}));
try {
const result = await searchAdminApi.recreateOpenSearchIndices();
const result = await searchAdminApi.recreateSolrIndices();
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
recreate: {
loading: false,
@@ -383,13 +383,13 @@ export default function SystemSettings({}: SystemSettingsProps) {
}));
setTimeout(() => {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
recreate: { loading: false, message: '', success: undefined }
}));
}, 8000);
} catch (error: any) {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
recreate: {
loading: false,
@@ -399,7 +399,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
}));
setTimeout(() => {
setOpenSearchStatus(prev => ({
setSolrStatus(prev => ({
...prev,
recreate: { loading: false, message: '', success: undefined }
}));
@@ -418,7 +418,7 @@ export default function SystemSettings({}: SystemSettingsProps) {
<div className="theme-card theme-shadow rounded-lg p-6">
<h2 className="text-xl font-semibold theme-header mb-4">Search Management</h2>
<p className="theme-text mb-6">
Manage OpenSearch indices for stories and authors. Use these tools if search isn't returning expected results.
Manage Solr indices for stories and authors. Use these tools if search isn't returning expected results.
</p>
<div className="space-y-6">
@@ -427,9 +427,9 @@ export default function SystemSettings({}: SystemSettingsProps) {
<h3 className="text-lg font-semibold theme-header mb-3">Search Status</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
<div className="flex justify-between">
<span>OpenSearch:</span>
<span className={`font-medium ${searchEngineStatus.openSearchAvailable ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
{searchEngineStatus.openSearchAvailable ? 'Available' : 'Unavailable'}
<span>Solr:</span>
<span className={`font-medium ${searchEngineStatus.solrAvailable ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}`}>
{searchEngineStatus.solrAvailable ? 'Available' : 'Unavailable'}
</span>
</div>
</div>
@@ -444,43 +444,43 @@ export default function SystemSettings({}: SystemSettingsProps) {
<div className="flex flex-col sm:flex-row gap-3 mb-4">
<Button
onClick={handleOpenSearchReindex}
disabled={openSearchStatus.reindex.loading || openSearchStatus.recreate.loading || !searchEngineStatus.openSearchAvailable}
loading={openSearchStatus.reindex.loading}
onClick={handleSolrReindex}
disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || !searchEngineStatus.solrAvailable}
loading={solrStatus.reindex.loading}
variant="ghost"
className="flex-1"
>
{openSearchStatus.reindex.loading ? 'Reindexing...' : '🔄 Reindex All'}
{solrStatus.reindex.loading ? 'Reindexing...' : '🔄 Reindex All'}
</Button>
<Button
onClick={handleOpenSearchRecreate}
disabled={openSearchStatus.reindex.loading || openSearchStatus.recreate.loading || !searchEngineStatus.openSearchAvailable}
loading={openSearchStatus.recreate.loading}
onClick={handleSolrRecreate}
disabled={solrStatus.reindex.loading || solrStatus.recreate.loading || !searchEngineStatus.solrAvailable}
loading={solrStatus.recreate.loading}
variant="secondary"
className="flex-1"
>
{openSearchStatus.recreate.loading ? 'Recreating...' : '🏗️ Recreate Indices'}
{solrStatus.recreate.loading ? 'Recreating...' : '🏗️ Recreate Indices'}
</Button>
</div>
{/* Status Messages */}
{openSearchStatus.reindex.message && (
{solrStatus.reindex.message && (
<div className={`text-sm p-3 rounded mb-3 ${
openSearchStatus.reindex.success
solrStatus.reindex.success
? 'bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200'
: 'bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200'
}`}>
{openSearchStatus.reindex.message}
{solrStatus.reindex.message}
</div>
)}
{openSearchStatus.recreate.message && (
{solrStatus.recreate.message && (
<div className={`text-sm p-3 rounded mb-3 ${
openSearchStatus.recreate.success
solrStatus.recreate.success
? 'bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200'
: 'bg-red-50 dark:bg-red-900/20 text-red-800 dark:text-red-200'
}`}>
{openSearchStatus.recreate.message}
{solrStatus.recreate.message}
</div>
)}
</div>

View File

@@ -576,7 +576,7 @@ export const searchAdminApi = {
getStatus: async (): Promise<{
primaryEngine: string;
dualWrite: boolean;
openSearchAvailable: boolean;
solrAvailable: boolean;
}> => {
const response = await api.get('/admin/search/status');
return response.data;
@@ -600,8 +600,8 @@ export const searchAdminApi = {
},
// Switch engines
switchToOpenSearch: async (): Promise<{ message: string }> => {
const response = await api.post('/admin/search/switch/opensearch');
switchToSolr: async (): Promise<{ message: string }> => {
const response = await api.post('/admin/search/switch/solr');
return response.data;
},
@@ -612,8 +612,8 @@ export const searchAdminApi = {
return response.data;
},
// OpenSearch operations
reindexOpenSearch: async (): Promise<{
// Solr operations
reindexSolr: async (): Promise<{
success: boolean;
message: string;
storiesCount?: number;
@@ -621,11 +621,11 @@ export const searchAdminApi = {
totalCount?: number;
error?: string;
}> => {
const response = await api.post('/admin/search/opensearch/reindex');
const response = await api.post('/admin/search/solr/reindex');
return response.data;
},
recreateOpenSearchIndices: async (): Promise<{
recreateSolrIndices: async (): Promise<{
success: boolean;
message: string;
storiesCount?: number;
@@ -633,7 +633,7 @@ export const searchAdminApi = {
totalCount?: number;
error?: string;
}> => {
const response = await api.post('/admin/search/opensearch/recreate');
const response = await api.post('/admin/search/solr/recreate');
return response.data;
},
};