3636import jakarta .json .JsonObjectBuilder ;
3737import jakarta .persistence .EntityManager ;
3838import jakarta .persistence .PersistenceContext ;
39+ import jakarta .persistence .Query ;
3940
4041import org .apache .solr .client .solrj .SolrServerException ;
4142import org .apache .solr .common .SolrInputDocument ;
@@ -410,41 +411,100 @@ public void indexDatasetBatchInNewTransaction(List<Long> datasetIds, final int[]
410411 indexPermissionsForOneDvObject (dataset );
411412
412413 // Process files for this dataset
413- for (DatasetVersion version : datasetVersionsToBuildCardsFor (dataset )) {
414- processDatasetVersionFiles (version , fileCounter , fileQueryMin , versions .size ()>1 );
414+ List <DatasetVersion > versions = datasetVersionsToBuildCardsFor (dataset );
415+ final List <Long > changedFileIds = new ArrayList <>();
416+ if (versions .size ()>1 ) {
417+ Long releasedVersionId = versions .get (versions .get (0 ).isReleased () ? 0 : 1 ).getId ();
418+ Long draftVersionId = versions .get (versions .get (0 ).isReleased () ? 1 : 0 ).getId ();
419+
420+ populateChangedFileIds (
421+ releasedVersionId ,
422+ draftVersionId ,
423+ changedFileIds
424+ );
425+ }
426+ for (DatasetVersion version : versions ) {
427+ processDatasetVersionFiles (version , fileCounter , fileQueryMin , (versions .size ()>1 && version .isDraft ()) ? changedFileIds : null );
415428 }
416429 }
417430 }
418431 }
419432
420433 @ TransactionAttribute (TransactionAttributeType .REQUIRES_NEW )
421434 public void indexDatasetFilesInNewTransaction (List <DatasetVersion > versions , final int [] fileCounter , int fileQueryMin ) {
435+ final List <Long > changedFileIds = new ArrayList <>();
436+ if (versions .size ()>1 ) {
437+ Long releasedVersionId = versions .get (versions .get (0 ).isReleased () ? 0 : 1 ).getId ();
438+ Long draftVersionId = versions .get (versions .get (0 ).isReleased () ? 1 : 0 ).getId ();
439+
440+ populateChangedFileIds (
441+ releasedVersionId ,
442+ draftVersionId ,
443+ changedFileIds
444+ );
445+ }
422446 for (DatasetVersion version : versions ) {
423447 // The version object is detached, but its fileMetadatas collection is already loaded.
424448 // We only need its ID and state, which are available.
425- processDatasetVersionFiles (version , fileCounter , fileQueryMin , versions .size ()>1 );
449+ processDatasetVersionFiles (version , fileCounter , fileQueryMin , ( versions .size ()>1 && version . isDraft ()) ? changedFileIds : null );
426450 }
427451 }
428452
453+ /**
454+ * Retrieves the IDs of file metadatas that have changed between the released version
455+ * and the draft version of a dataset.
456+ *
457+ * @param releasedVersionId the ID of the released dataset version
458+ * @param draftVersionId the ID of the draft dataset version
459+ * @param changedFileMetadataIds the list to populate with changed file metadata IDs
460+ */
461+ protected void populateChangedFileIds (Long releasedVersionId , Long draftVersionId , List <Long > changedFileIds ) {
462+ Query query = em .createNamedQuery ("FileMetadata.getDatafilesWithChangedMetadata" , Long .class );
463+ query .setParameter (1 , releasedVersionId );
464+ query .setParameter (2 , draftVersionId );
465+
466+ /*
467+ * When the query was configured to return Long, it was returning Integer.
468+ * The query has been changed to return Integer now. The code here is robust
469+ * if that changes in the future.
470+ */
471+ List <Object > queryResults = query .getResultList ();
472+ for (Object result : queryResults ) {
473+ if (result != null ) {
474+ // Ensure we're adding Long objects to the list
475+ if (result instanceof Integer intResult ) {
476+ logger .finest ("Converted Integer result to Long: " + result );
477+ changedFileIds .add (Long .valueOf (intResult ));
478+ } else if (result instanceof Long longResult ) {
479+ // Already a Long, add directly
480+ logger .finest ("Added existing Long to list: " + result );
481+ changedFileIds .add (longResult );
482+ } else {
483+ // If it's not a Long, convert it to one via String
484+ try {
485+ changedFileIds .add (Long .valueOf (result .toString ()));
486+ logger .finest ("Converted non-Long result to Long: " + result + " of type " + result .getClass ().getName ());
487+ } catch (NumberFormatException e ) {
488+ logger .warning ("Could not convert query result to Long: " + result );
489+ }
490+ }
491+ }
492+ }
493+ }
494+
429495 private void processDatasetVersionFiles (DatasetVersion version ,
430- final int [] fileCounter , int fileQueryMin , boolean isReleased ) {
496+ final int [] fileCounter , int fileQueryMin , List < Long > changedFileIds ) {
431497 List <String > cachedPerms = searchPermissionsService .findDatasetVersionPerms (version );
432498 String solrIdEnd = getDatasetOrDataFileSolrEnding (version .getVersionState ());
433499 Long versionId = version .getId ();
434500 List <DataFileProxy > filesToReindexAsBatch = new ArrayList <>();
435501
436502 // If the version is draft and there is a released version,
437- // we only need perm docs for the files with filemetadata changes == those with _draft solr docs already
438- Set <Long > fileIdsToReindex = null ;
439- if (version .getVersionState ().equals (DatasetVersion .VersionState .DRAFT ) && isReleased ) {
440- fileIdsToReindex = getFileIdsWithSolrDocs (versionId );
441- logger .fine ("Found " + fileIdsToReindex .size () + " files with draft Solr docs for version " + versionId );
442- }
503+ // we only need perm docs for the files with filemetadata changes == those in changedFileMetadataIds
443504
444505 // Process files in batches of 100
445506 int batchSize = 100 ;
446507
447- final Set <Long > finalFileIdsToReindex = fileIdsToReindex ;
448508 if (dataFileService .findCountByDatasetVersionId (version .getId ()).intValue () > fileQueryMin ) {
449509 // For large datasets, use a more efficient SQL query
450510 // ToDo - only get the ones in finalFileIdsToReindex
@@ -453,7 +513,7 @@ private void processDatasetVersionFiles(DatasetVersion version,
453513 // Process files in batches to avoid memory issues
454514 fileStream .forEach (fileInfo -> {
455515 // Only add files that need reindexing
456- if (finalFileIdsToReindex == null || finalFileIdsToReindex .contains (fileInfo .getFileId ())) {
516+ if (changedFileIds == null || changedFileIds .contains (fileInfo .getFileId ())) {
457517 filesToReindexAsBatch .add (fileInfo );
458518 fileCounter [0 ]++;
459519
@@ -470,7 +530,7 @@ private void processDatasetVersionFiles(DatasetVersion version,
470530 for (FileMetadata fmd : version .getFileMetadatas ()) {
471531 // Only add files that need reindexing
472532 DataFileProxy fileProxy = new DataFileProxy (fmd );
473- if (finalFileIdsToReindex == null || finalFileIdsToReindex .contains (fileProxy .getFileId ())) {
533+ if (changedFileIds == null || changedFileIds .contains (fileProxy .getFileId ())) {
474534 filesToReindexAsBatch .add (fileProxy );
475535 fileCounter [0 ]++;
476536
@@ -510,55 +570,6 @@ private void reindexFilesInBatches(List<DataFileProxy> filesToReindexAsBatch, Li
510570 }
511571 }
512572
513- /**
514- * Queries Solr to find file IDs that have draft documents for the given dataset version.
515- * This is used to optimize permission reindexing by only processing files that have
516- * metadata changes in the draft version.
517- *
518- * @param datasetVersionId The ID of the dataset version
519- * @return A set of file IDs that have Solr documents associated with this version
520- */
521- private Set <Long > getFileIdsWithSolrDocs (Long datasetVersionId ) {
522- Set <Long > fileIds = new HashSet <>();
523-
524- try {
525- SolrQuery solrQuery = new SolrQuery ();
526-
527- // Query for files in this specific version with draft suffix
528- solrQuery .setQuery ("*:*" );
529- solrQuery .addFilterQuery (SearchFields .TYPE + ":" + SearchConstants .FILES );
530- solrQuery .addFilterQuery (SearchFields .DATASET_VERSION_ID + ":" + datasetVersionId );
531-
532- // Only return the entity ID field
533- solrQuery .setFields (SearchFields .ENTITY_ID );
534-
535- // We want all matching documents
536- solrQuery .setRows (Integer .MAX_VALUE );
537-
538- logger .fine ("Solr query to find draft files: " + solrQuery );
539-
540- QueryResponse queryResponse = solrClientService .getSolrClient ().query (solrQuery );
541- SolrDocumentList docs = queryResponse .getResults ();
542-
543- for (SolrDocument doc : docs ) {
544- Long entityId = (Long ) doc .getFieldValue (SearchFields .ENTITY_ID );
545- if (entityId != null ) {
546- fileIds .add (entityId );
547- }
548- }
549-
550- logger .fine ("Found " + fileIds .size () + " files with draft Solr docs for version " + datasetVersionId );
551-
552- } catch (SolrServerException | IOException ex ) {
553- logger .log (Level .WARNING , "Error querying Solr for draft file IDs for version " + datasetVersionId +
554- ". Will reindex all files as fallback." , ex );
555- // Return null to indicate we should process all files
556- return null ;
557- }
558-
559- return fileIds ;
560- }
561-
562573 public IndexResponse deleteMultipleSolrIds (List <String > solrIdsToDelete ) {
563574 if (solrIdsToDelete .isEmpty ()) {
564575 return new IndexResponse ("nothing to delete" );
0 commit comments