You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ctakes.apache.org by se...@apache.org on 2026/03/09 16:02:55 UTC
(ctakes) branch main updated: raised private to protected methods in AbstractTableFileWriter Improved add Date/Time methods in CalendarUtil Updated ctakes_types.py PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly Update ZipFileTreeReader to use note type and dates in filenames if present
This is an automated email from the ASF dual-hosted git repository.
seanfinan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ctakes.git
The following commit(s) were added to refs/heads/main by this push:
new 9f4590b raised private to protected methods in AbstractTableFileWriter Improved add Date/Time methods in CalendarUtil Updated ctakes_types.py PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly Update ZipFileTreeReader to use note type and dates in filenames if present
9f4590b is described below
commit 9f4590b721eb0727076d80c48a1c9ad232f8a2b6
Author: Sean Finan <se...@childrens.harvard.edu>
AuthorDate: Mon Mar 9 12:02:33 2026 -0400
raised private to protected methods in AbstractTableFileWriter
Improved add Date/Time methods in CalendarUtil
Updated ctakes_types.py
PatientMedTableFileWriter appends rows instead of one big write, outputs first mention doc time
Added logging.basicConfig to pbj_pipeline.py and updated other pbj logging accordingly
Update ZipFileTreeReader to use note type and dates in filenames if present
---
.../ctakes/core/cc/AbstractTableFileWriter.java | 22 +-
.../ctakes/core/cc/PatientMedTableFileWriter.java | 269 +++++++++++++++++----
.../apache/ctakes/core/cr/ZipFileTreeReader.java | 103 +++++---
.../org/apache/ctakes/core/util/CalendarUtil.java | 73 ++++--
.../src/ctakes_pbj/component/pbj_dir_reader.py | 22 +-
.../src/ctakes_pbj/component/pbj_sender.py | 10 +-
.../src/ctakes_pbj/pbj_tools/stomp_receiver.py | 15 +-
.../src/ctakes_pbj/pipeline/pbj_pipeline.py | 28 ++-
.../src/ctakes_pbj/type_system/ctakes_types.py | 25 +-
.../ctakes_pbj/type_system/type_system_loader.py | 3 +-
.../org/apache/ctakes/pbj/types/TypeSystem.xml | 218 ++++++++++++++---
ctakes-ytex-uima/pom.xml | 40 +--
12 files changed, 641 insertions(+), 187 deletions(-)
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
index f3aa157..f4d80c9 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/AbstractTableFileWriter.java
@@ -149,6 +149,25 @@ abstract public class AbstractTableFileWriter
protected void writeComplete( final List<List<String>> data ) {
}
+ protected TableType getTableType() {
+ return Arrays.stream( TableType.values() )
+ .filter( s -> s.name().equalsIgnoreCase( _tableType ) )
+ .findFirst()
+ .orElse( TableType.BSV );
+ }
+
+ // TODO - refactor up to AbstractFileWriter
+ protected File getOutputFile( final String outputDir,
+ final String documentId,
+ final String fileName ) {
+ final TableType tableType = Arrays.stream( TableType.values() )
+ .filter( s -> s.name()
+ .equalsIgnoreCase( _tableType ) )
+ .findFirst()
+ .orElse( TableType.BSV );
+ return new File( outputDir, documentId + "_table." + tableType.name() );
+ }
+
/**
* {@inheritDoc}
*/
@@ -157,15 +176,14 @@ abstract public class AbstractTableFileWriter
final String outputDir,
final String documentId,
final String fileName ) throws IOException {
+ final File file = getOutputFile( outputDir, documentId, fileName );
final TableType tableType = Arrays.stream( TableType.values() )
.filter( s -> s.name()
.equalsIgnoreCase( _tableType ) )
.findFirst()
.orElse( TableType.BSV );
- final File file = new File( outputDir, documentId + "_table." + tableType.name() );
LOGGER.info( "Writing {} Table to {} ...", tableType.name(), file.getPath() );
final String header = createTableHeader( tableType, getHeaderRow() );
-
final String footer = createTableFooter( tableType, getFooterRow() );
try ( Writer writer = new BufferedWriter( new FileWriter( file ) ) ) {
writer.write( header );
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
index de85952..a6caca3 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cc/PatientMedTableFileWriter.java
@@ -3,16 +3,27 @@ package org.apache.ctakes.core.cc;
import org.apache.ctakes.core.pipeline.PipeBitInfo;
import org.apache.ctakes.core.util.annotation.IdentifiedAnnotationUtil;
import org.apache.ctakes.core.util.doc.DocIdUtil;
+import org.apache.ctakes.core.util.doc.SourceMetadataUtil;
import org.apache.ctakes.typesystem.type.structured.Patient;
+import org.apache.ctakes.typesystem.type.structured.SourceData;
import org.apache.ctakes.typesystem.type.textsem.MedicationMention;
+import org.apache.uima.UimaContext;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
+import org.apache.uima.fit.descriptor.ConfigurationParameter;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.jcas.JCas;
+import org.apache.uima.resource.ResourceInitializationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
+import java.io.*;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
import java.util.*;
+import java.util.stream.Collectors;
import static org.apache.ctakes.core.pipeline.PipeBitInfo.TypeProduct.*;
@@ -32,9 +43,50 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
// If you do not need to utilize the entire cas, or need more than the doc cas, consider AbstractFileWriter<T>.
static private final Logger LOGGER = LoggerFactory.getLogger( "PatientMedTableFileWriter" );
+ static public final String DATE_WRITE_FORMAT_PARAM = "DateWriteFormat";
+ static public final String DATE_WRITE_FORMAT_DESC = "A format to write dates. e.g. dd-MM-yyyy_HH:mm:ss";
+ @ConfigurationParameter (
+ name = DATE_WRITE_FORMAT_PARAM,
+ description = DATE_WRITE_FORMAT_DESC,
+ defaultValue = "ddMMyyyykkmmss",
+ mandatory = false
+ )
+ private String _dateWriteFormat;
+
+ static public final String CAS_DATE_FORMAT_PARAM = "CasDateFormat";
+ static public final String CAS_DATE_FORMAT_DESC = "Set a value for parameter CasDateFormat.";
+ @ConfigurationParameter (
+ name = CAS_DATE_FORMAT_PARAM,
+ description = CAS_DATE_FORMAT_DESC,
+ defaultValue = "MMddyyyykkmmss",
+ mandatory = false
+ )
+ private String _casDateFormat;
+
+ private DateTimeFormatter _dateWriteFormatter;
+ private DateTimeFormatter _casDateFormatter;
+
private int _patientDocCount = 0;
- private final Map<String,PatientMed> _patientMeds = new HashMap<>();
- private final Map<String,Integer> _patientMedCounts = new HashMap<>();
+// private final Map<String,PatientMed> _patientMeds = new HashMap<>();
+// private final Map<String,Integer> _patientMedCounts = new HashMap<>();
+ private boolean _isFirstWrite = true;
+
+ static private final LocalDateTime TODAY_DATE = LocalDateTime.now();
+ private String _runStartTime;
+
+ private MedCell _medCell;
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize( final UimaContext context ) throws ResourceInitializationException {
+ super.initialize( context );
+ _casDateFormatter = DateTimeFormatter.ofPattern( _casDateFormat );
+ _dateWriteFormatter = DateTimeFormatter.ofPattern( _dateWriteFormat );
+ _runStartTime = _casDateFormatter.format( OffsetDateTime.now() );
+ }
/**
* Add medication data from the cas to table rows.
@@ -42,11 +94,19 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
*/
@Override
public void process( final JCas jcas ) throws AnalysisEngineProcessException {
- final List<List<String>> dataRows = createDataRows( jcas );
- if ( dataRows.isEmpty() ) {
+ createData( jcas );
+ final List<List<String>> data = getData();
+ if ( data == null || data.isEmpty() ) {
+ // Not done with patient.
return;
}
- dataRows.forEach( this::addDataRow );
+ // Done with patient, append data to file.
+ try {
+ appendFile( data, "", "", "", _isFirstWrite, false );
+ } catch ( IOException ioE ) {
+ throw new AnalysisEngineProcessException( ioE );
+ }
+ _isFirstWrite = false;
}
/**
@@ -55,11 +115,9 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
*/
@Override
public void collectionProcessComplete() throws AnalysisEngineProcessException {
- setHeaderRow( createHeaderRow( null ) );
- final List<List<String>> data = getData();
try {
- writeFile( data, getOutputDirectory( null, getRootDirectory(), null ), "PatientMedication", "" );
- writeComplete( data );
+ appendFile( Collections.emptyList(), "", "", "", _isFirstWrite, true );
+ writeComplete( Collections.emptyList() );
} catch ( IOException ioE ) {
throw new AnalysisEngineProcessException( ioE );
}
@@ -75,28 +133,52 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
return getSimpleSubDirectory();
}
+ // TODO - refactor up to AbstractFileWriter
+ protected File getOutputFile( final String outputDir,
+ final String documentId,
+ final String fileName ) {
+ final String simpleOutputDir = getOutputDirectory( null, getRootDirectory(), null );
+ return super.getOutputFile( simpleOutputDir, "PatientMedication_"+_runStartTime, "" );
+ }
+
/**
- * Patient ID, Medication Names, CUI, RNorm, NCI Cui, Count
* {@inheritDoc}
*/
- @Override
- protected List<String> createHeaderRow( final JCas jCas ) {
- return Arrays.asList(
- " Patient ID ",
- " Medication Names ",
- " CUI ",
- " RxNorm ",
- " NCI Cui ",
- " Count " );
+ public void appendFile( final List<List<String>> dataRows,
+ final String outputDir,
+ final String documentId,
+ final String fileName,
+ final boolean writeHeader,
+ final boolean writeFooter ) throws IOException {
+ final TableType tableType = getTableType();
+ final File file = getOutputFile( outputDir, documentId, fileName );
+ LOGGER.info( "Appending {} Table to {} ...", tableType.name(), file.getPath() );
+ try ( Writer writer = new BufferedWriter( new FileWriter( file, true ) ) ) {
+ if ( writeHeader ) {
+ final String header = createTableHeader( tableType, getHeaderRow() );
+ writer.write( header );
+ }
+ for ( List<String> dataRow : dataRows ) {
+ final String row = createTableRow( tableType, dataRow );
+ writer.write( row );
+ }
+ if ( writeFooter ) {
+ final String footer = createTableFooter( tableType, getFooterRow() );
+ writer.write( footer );
+ }
+ }
}
/**
- * Does nothing.
- * @param jCas the jcas passed to the process( jcas ) method.
+ * Patient ID, Medication Names, CUI, RNorm, NCI Cui, Count
+ * {@inheritDoc}
*/
@Override
- protected void createData( final JCas jCas ) {
- return;
+ protected List<String> createHeaderRow( final JCas jCas ) {
+ return Arrays.asList(
+ " Patient ID ",
+ " Medications (Name, [CUIs], [RxNorms], [NCI Cuis], earliest evidence ddMMyyyy240000, count) ",
+ " document count " );
}
/**
@@ -112,14 +194,18 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
LOGGER.error( "No Patient for doc {}", DocIdUtil.getDocumentID( jCas ) );
System.exit( -1 );
}
-
+ final LocalDateTime docDate = getDocDate( jCas );
+ if ( _medCell == null ) {
+ _medCell = new MedCell();
+ }
// Get the medication mentions,
// turn each medication mention into a PatientMedRecord,
// add each PatientMedRecord to the map (uniquely), increasing a count of identical meds.
for ( MedicationMention med : JCasUtil.select( jCas, MedicationMention.class ) ) {
- final String name = IdentifiedAnnotationUtil.getPreferredText( med );
- _patientMeds.put( name, new PatientMed( med ) );
- _patientMedCounts.merge( name, 1, Integer::sum );
+ _medCell.update( new PatientMed( med ), docDate );
+// final String name = IdentifiedAnnotationUtil.getPreferredText( med );
+// _patientMeds.put( name, new PatientMed( med ) );
+// _patientMedCounts.merge( name, 1, Integer::sum );
}
// Increase the internal count of documents processed.
_patientDocCount++;
@@ -133,6 +219,25 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
return Collections.singletonList( createTableRow( patient.getPatientIdentifier() ) );
}
+ private LocalDateTime getDocDate( final JCas jCas ) {
+ final SourceData sourceData = SourceMetadataUtil.getOrCreateSourceData( jCas );
+ String casDate = sourceData.getSourceRevisionDate();
+ if ( casDate == null || casDate.isEmpty() ) {
+ casDate = sourceData.getSourceOriginalDate();
+ }
+ if ( casDate == null || casDate.isEmpty() ) {
+ return TODAY_DATE;
+ }
+// LOGGER.info( "Cas Date " + casDate + " Run Start " + _runStartTime );
+ LocalDateTime dateTime;
+ try {
+ dateTime = LocalDateTime.parse( casDate, _casDateFormatter );
+ } catch ( DateTimeParseException dtpE ) {
+ final LocalDate date = LocalDate.parse( casDate, _casDateFormatter );
+ dateTime = date.atStartOfDay();
+ }
+ return dateTime;
+ }
/**
* Create single table row with information from all PatientMeds.
@@ -140,30 +245,36 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
* @return -
*/
private List<String> createTableRow( final String patientId ) {
- final List<String> names
- = _patientMeds.keySet().stream()
- .sorted( String.CASE_INSENSITIVE_ORDER )
- .toList();
- final StringBuilder prefTexts = new StringBuilder();
- final StringBuilder cuis = new StringBuilder();
- final StringBuilder rxnorms = new StringBuilder();
- final StringBuilder nciCuis = new StringBuilder();
- final StringBuilder counts = new StringBuilder();
- for ( String name : names ) {
- PatientMed med = _patientMeds.get( name );
- prefTexts.append( name ).append( ";" );
- cuis.append( med.cuis ).append( ";" );
- rxnorms.append( med.rxnorms ).append( ";" );
- nciCuis.append( med.nciCuis ).append( ";" );
- counts.append( _patientMedCounts.get( name ) ).append( ";" );
+ if ( _medCell == null ) {
+ return Arrays.asList( patientId, "", ""+_patientDocCount );
}
- return Arrays.asList(
- patientId,
- prefTexts.toString(),
- cuis.toString(),
- rxnorms.toString(),
- nciCuis.toString(),
- counts.toString() );
+ final String cell = _medCell.getCell();
+ _medCell = null;
+ return Arrays.asList( patientId, cell, ""+_patientDocCount );
+// final List<String> names
+// = _patientMeds.keySet().stream()
+// .sorted( String.CASE_INSENSITIVE_ORDER )
+// .toList();
+// final StringBuilder prefTexts = new StringBuilder();
+// final StringBuilder cuis = new StringBuilder();
+// final StringBuilder rxnorms = new StringBuilder();
+// final StringBuilder nciCuis = new StringBuilder();
+// final StringBuilder counts = new StringBuilder();
+// for ( String name : names ) {
+// PatientMed med = _patientMeds.get( name );
+// prefTexts.append( name ).append( ";" );
+// cuis.append( med.cuis ).append( ";" );
+// rxnorms.append( med.rxnorms ).append( ";" );
+// nciCuis.append( med.nciCuis ).append( ";" );
+// counts.append( _patientMedCounts.get( name ) ).append( ";" );
+// }
+// return Arrays.asList(
+// patientId,
+// prefTexts.toString(),
+// cuis.toString(),
+// rxnorms.toString(),
+// nciCuis.toString(),
+// counts.toString() );
}
@@ -181,14 +292,66 @@ public class PatientMedTableFileWriter extends AbstractTableFileWriter {
* @param rxnorms -
* @param nciCuis -
*/
- private record PatientMed( List<String> cuis,
+ private record PatientMed( String name,
+ List<String> cuis,
List<String> rxnorms,
List<String> nciCuis ) {
private PatientMed( final MedicationMention med ) {
- this( toSortedList( IdentifiedAnnotationUtil.getCuis( med ) ),
+ this( IdentifiedAnnotationUtil.getPreferredText( med ),
+ toSortedList( IdentifiedAnnotationUtil.getCuis( med ) ),
toSortedList( IdentifiedAnnotationUtil.getCodes( med, "RXNORM" ) ),
toSortedList( IdentifiedAnnotationUtil.getCodes( med, "NCI" ) ) );
}
}
+
+ private class MedCell {
+ final private Map<String, LocalDateTime> _nameDateMap = new HashMap<>();
+ final private Map<String, PatientMed> _nameMedMap = new HashMap<>();
+ private final Map<String,Integer> _nameCounts = new HashMap<>();
+
+ private void update( final Collection<PatientMed> patientMeds, final LocalDateTime docDate ) {
+ patientMeds.forEach( m -> update( m, docDate ) );
+ }
+
+ private void update( final PatientMed patientMed , final LocalDateTime docDate ) {
+ final String name = patientMed.name();
+ final LocalDateTime statusDate = _nameDateMap.get( name );
+ if ( statusDate == null ) {
+ _nameDateMap.put( name, docDate );
+ _nameMedMap.put( name, patientMed );
+ } else if ( docDate.isBefore( statusDate ) ) {
+ _nameDateMap.put( name, docDate );
+ }
+ _nameCounts.merge( name, 1, Integer::sum );
+ }
+
+ private boolean hasInfo() {
+ return !_nameDateMap.isEmpty();
+ }
+
+ private String getCell() {
+ return _nameMedMap.keySet()
+ .stream()
+ .sorted()
+ .map( this::getValueCell )
+ .collect( Collectors.joining( ";" ) );
+ }
+
+ private String getValueCell( final String name ) {
+ final LocalDateTime date = _nameDateMap.get( name );
+ if ( date == null ) {
+ return "";
+ }
+ PatientMed med = _nameMedMap.get( name );
+ return name + ',' +
+ med.cuis() + ',' +
+ med.rxnorms() + ',' +
+ med.nciCuis() + ',' +
+ date.format( _dateWriteFormatter ) + ',' +
+ _nameCounts.get( name );
+ }
+ }
+
+
}
\ No newline at end of file
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java b/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
index 2a8656b..e82ea3e 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/cr/ZipFileTreeReader.java
@@ -3,9 +3,7 @@ package org.apache.ctakes.core.cr;
import org.apache.ctakes.core.patient.PatientNoteStore;
import org.apache.ctakes.core.pipeline.PipeBitInfo;
import org.apache.ctakes.core.pipeline.ProgressManager;
-import org.apache.ctakes.core.util.AeParamUtil;
-import org.apache.ctakes.core.util.BannerWriter;
-import org.apache.ctakes.core.util.NumberedSuffixComparator;
+import org.apache.ctakes.core.util.*;
import org.apache.ctakes.core.util.doc.DocIdUtil;
import org.apache.ctakes.core.util.doc.JCasBuilder;
import org.apache.ctakes.core.util.doc.SourceMetadataUtil;
@@ -23,11 +21,11 @@ import org.slf4j.LoggerFactory;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
-import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -62,17 +60,15 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
)
private String _patientListPath;
-// static public final String DATE_FORMAT_PARAM = "DateFormat";
-// static public final String DATE_FORMAT_DESC = "A format to parse dates. e.g. dd-MM-yyyy_HH:mm:ss";
-// @ConfigurationParameter (
-// name = DATE_FORMAT_PARAM,
-// description = DATE_FORMAT_DESC,
-// defaultValue = "yyyyMMdd",
-// mandatory = false
-// )
-// private String _dateFormat;
-//
-// private DateTimeFormatter _dateFormatter;
+ static public final String FILE_DATE_FORMAT_PARAM = "FileDateFormat";
+ static public final String FILE_DATE_FORMAT_DESC = "A format to parse date from a filename. e.g. dd-MM-yyyy_HH:mm:ss";
+ @ConfigurationParameter (
+ name = FILE_DATE_FORMAT_PARAM,
+ description = FILE_DATE_FORMAT_DESC,
+ defaultValue = "yyyyMMdd",
+ mandatory = false
+ )
+ private String _fileDateFormat;
static public final String CAS_DATE_FORMAT_PARAM = "CasDateFormat";
static public final String CAS_DATE_FORMAT_DESC = "Set a value for parameter CasDateFormat.";
@@ -84,7 +80,11 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
)
private String _casDateFormat;
+ private DateTimeFormatter _fileDateFormatter;
private DateTimeFormatter _casDateFormatter;
+ private final String SHORT_DATE_FORMAT = "yyMMdd";
+ private final DateTimeFormatter SHORT_DATE_FORMATTER = DateTimeFormatter.ofPattern( SHORT_DATE_FORMAT );
+ private final LocalDateTime RUN_START_DT = LocalDateTime.now();
private boolean _writeBanner_ = false;
@@ -114,7 +114,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
@Override
public void initialize( final UimaContext context ) throws ResourceInitializationException {
super.initialize( context );
-// _dateFormatter = DateTimeFormatter.ofPattern( _dateFormat );
+ _fileDateFormatter = DateTimeFormatter.ofPattern( _fileDateFormat );
_casDateFormatter = DateTimeFormatter.ofPattern( _casDateFormat );
// TODO - for zipPatientLevel in the zip getPatient just get the dir at that level.
final Object zipPatientLevel = context.getConfigParameterValue( PATIENT_LEVEL );
@@ -139,6 +139,13 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
// Get rid of patients named after source subdirectories.
final Collection<String> subDirPatients = PatientNoteStore.getInstance().getStoredPatientIds();
subDirPatients.forEach( PatientNoteStore.getInstance()::removePatient );
+ if ( !SHORT_DATE_FORMAT.equals( _fileDateFormat ) ) {
+ CalendarUtil.addDateFormat( _fileDateFormat );
+ }
+ if ( !SHORT_DATE_FORMAT.equals( _casDateFormat ) ) {
+ CalendarUtil.addDateTimeFormat( _casDateFormat );
+ }
+ CalendarUtil.addDateFormat( SHORT_DATE_FORMAT );
}
// TODO move to super class
@@ -455,6 +462,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
final String idPrefix = createDocumentIdPrefix( entryFile, getRootDir() );
final String docType = createDocumentType( id );
final String docTime = createDocumentTime( entry );
+ final Calendar creationDate = CalendarUtil.getCalendar( docTime );
final String patientId = getPatientId( entry );
return new JCasBuilder()
.setCorpusName( getCorpusName() )
@@ -466,6 +474,7 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
.setDocIdPrefix( idPrefix )
.setDocType( docType )
.setDocTime( docTime )
+ .setDocCreationDate( creationDate )
.setDocPath( entryPath )
.nullDocText();
} catch ( IOException ioE ) {
@@ -542,15 +551,16 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
return file.getParent();
}
-
- /**
- * @param entry -
- * @return the file's last modification date as a string : {@link #getDateFormat()}
- */
- protected String createDocumentTime( final ZipEntry entry ) {
- return createDocumentTime( entry.getTime() );
+ protected String createDocumentType( final String documentId ) {
+ final String[] splits = StringUtil.fastSplit( documentId, '-' );
+ if ( splits.length == 4 ) {
+ return splits[ 2 ];
+ }
+ return super.createDocumentType( documentId );
}
+
+
// TODO move to abstract reader
/**
@@ -558,31 +568,54 @@ public class ZipFileTreeReader extends AbstractFileTreeReader {
*/
@Override
public DateFormat getDateFormat() {
-// return new SimpleDateFormat( _dateFormat );
return new SimpleDateFormat( _casDateFormat );
}
- protected String createDocumentTime( final LocalDate date ) {
- return _casDateFormatter.format( date );
- }
-
protected String createDocumentTime( final LocalDateTime dateTime ) {
return _casDateFormatter.format( dateTime );
}
/**
- * @param millis -
+ * @param entry -
* @return the file's last modification date as a string : {@link #getDateFormat()}
*/
- // TODO move to super class
- protected String createDocumentTime( final long millis ) {
-// _dateFormatter = DateTimeFormatter.ofPattern( _dateFormat );
-// return _dateFormatter.format(
- return _casDateFormatter.format(
- LocalDateTime.ofInstant( Instant.ofEpochMilli( millis ), ZONE_ID ) );
+ protected String createDocumentTime( final ZipEntry entry ) {
+ final File entryFile = new File( entry.getName() );
+ final String entryName = entryFile.getName();
+ final String[] extSplits = StringUtil.fastSplit( entryName, '.' );
+ final String[] splits = StringUtil.fastSplit( extSplits[ 0 ], '-' );
+ if ( splits.length == 4 ) {
+ final LocalDateTime ldt = getLocalDateTime( splits[ 3 ] );
+ return createDocumentTime( ldt );
+ }
+ return createDocumentTime( RUN_START_DT );
}
+ // TODO move to abstract reader
+
+ private LocalDateTime getLocalDateTime( final String dateText ) {
+ LocalDate date = null;
+ if ( dateText.length() == 8 ) {
+ try {
+ date = LocalDate.parse( dateText, _fileDateFormatter );
+ } catch ( DateTimeParseException dtpE ) {
+ LOGGER.warn( "Bad File date {} {}", _fileDateFormat, dateText );
+ }
+ } else if ( dateText.length() == 6 ) {
+ try {
+ date = LocalDate.parse( dateText, SHORT_DATE_FORMATTER );
+ } catch ( DateTimeParseException dtpE ) {
+ LOGGER.warn( "Bad File short date {} {}", SHORT_DATE_FORMAT, dateText );
+ }
+ } else {
+ LOGGER.warn( "Bad File date length {}", dateText );
+ }
+ if ( date != null ) {
+ return date.atStartOfDay();
+ }
+ return RUN_START_DT;
+ }
}
\ No newline at end of file
diff --git a/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java b/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
index 544e5e4..109b0c9 100644
--- a/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
+++ b/ctakes-core/src/main/java/org/apache/ctakes/core/util/CalendarUtil.java
@@ -69,26 +69,71 @@ final public class CalendarUtil {
= new IdentifiedAnnotationBuilder().creator( TimeMention::new )
.type( SemanticTui.T079 );
- static {
+ static {
for ( String date : DATE_FORMAT_CODES ) {
- DATE_FORMATS.add( new SimpleDateFormat( date ) );
- DATE_FORMATS.add( new SimpleDateFormat( "EEE " + date ) );
- DATE_FORMATS.add( new SimpleDateFormat( "EEE, " + date ) );
+ addDateFormats( date );
for ( String time : TIME_FORMAT_CODES ) {
- DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " " + time ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " 'at' " + time ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE " + date + " " + time ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE, " + date + " 'at' " + time ) );
-
- DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " " + date ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' " + date ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( time + ", EEE " + date ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE " + date ) );
- DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE, " + date ) );
+ addDateTimeFormats( date, time );
}
}
}
+ static private void addDateFormats( final String date ) {
+ DATE_FORMATS.add( new SimpleDateFormat( date ) );
+ DATE_FORMATS.add( new SimpleDateFormat( "EEE " + date ) );
+ DATE_FORMATS.add( new SimpleDateFormat( "EEE, " + date ) );
+ }
+
+ static private void addTimeFormats( final String time ) {
+ for ( String date : DATE_FORMAT_CODES ) {
+ addDateTimeFormats( date, time );
+ }
+ }
+
+
+ static private void addDateTimeFormats( final String date, final String time ) {
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " " + time ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( date + " 'at' " + time ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE " + date + " " + time ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( "EEE, " + date + " 'at' " + time ) );
+
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " " + date ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' " + date ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( time + ", EEE " + date ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE " + date ) );
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( time + " 'on' EEE, " + date ) );
+ }
+
+
+ /**
+ * To normalize date and time expressions, a number of date and time formats are tested.
+ * This will add a date format to the known list of date and time expressions.
+ * @param dateFormat for SimpleDateFormat to apply for normalization.
+ */
+ static public void addDateFormat( final String dateFormat ) {
+ addDateFormats( dateFormat );
+ for ( String time : TIME_FORMAT_CODES ) {
+ addDateTimeFormats( dateFormat, time );
+ }
+ }
+
+ /**
+ * To normalize date and time expressions, a number of date and time formats are tested.
+ * This will add a time format to the known list of date and time expressions.
+ * @param timeFormat for SimpleDateFormat to apply for normalization.
+ */
+ static public void addTimeFormat( final String timeFormat ) {
+ addTimeFormats( timeFormat );
+ }
+
+ /**
+ * To normalize date and time expressions, a number of date and time formats are tested.
+ * This will add a date and time format to the known list of date and time expressions.
+ * @param dateTimeFormat for SimpleDateFormat to apply for normalization.
+ */
+ static public void addDateTimeFormat( final String dateTimeFormat ) {
+ DATE_TIME_FORMATS.add( new SimpleDateFormat( dateTimeFormat ) );
+ }
/**
* @param jCas ye olde ...
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
index 14b75ce..d3d65c8 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_dir_reader.py
@@ -1,7 +1,7 @@
-import sys
import os
from ctakes_pbj.component.collection_reader import CollectionReader
from ctakes_pbj.type_system.type_system_loader import *
+from cassis import Cas
import logging
@@ -13,6 +13,7 @@ class PBJDirReader(CollectionReader):
def __init__(self):
self.input_dir = None
+ self.typesystem = None
self.pipeline = None
# Set the pipeline. The collection reader controls the pipeline flow.
@@ -36,6 +37,7 @@ def init_params(self, args):
# Called start reading cas objects and pass them to the pipeline.
def start(self):
+ logger.info(f"Starting Directory Reader on {self.input_dir}...")
for filename in os.listdir(self.input_dir):
filepath = os.path.join(self.input_dir, filename)
if os.path.isfile(filepath):
@@ -46,3 +48,21 @@ def start(self):
document_language="en",
typesystem=self.get_typesystem())
self.pipeline.process(cas)
+ logger.info(f"Finished reading {self.input_dir}.")
+ self.stop()
+
+ # Called to stop reading.
+ def stop(self):
+ # logger.info("%s PBJ Dir Reader: Stopping Pipeline ...", time.ctime())
+ self.pipeline.collection_process_complete()
+
+ def set_typesystem(self, typesystem):
+ self.typesystem = typesystem
+
+ def get_typesystem(self):
+ if self.typesystem is None:
+ # Load the typesystem
+ type_system_accessor = TypeSystemLoader()
+ type_system_accessor.load_type_system()
+ self.set_typesystem(type_system_accessor.get_type_system())
+ return self.typesystem
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
index 3547d98..ca715a9 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/component/pbj_sender.py
@@ -1,5 +1,4 @@
import sys
-import time
import stomp
import logging
@@ -43,7 +42,7 @@ def init_params(self, args):
# Called once at the beginning of a pipeline.
def initialize(self):
- logger.info(f"{time.ctime()} Starting PBJ Sender on {self.host} {self.queue} ...")
+ logger.info(f"Starting PBJ Sender on {self.host} {self.queue} ...")
# Use a heartbeat of 10 minutes (in milliseconds)
self.conn = stomp.Connection12([(self.host, self.port)],
keepalive=True, heartbeats=(600000, 600000))
@@ -51,8 +50,7 @@ def initialize(self):
# Called for every cas passed through the pipeline.
def process(self, cas):
- logger.info(time.ctime(), "Sending processed information to",
- self.host, self.queue, "...")
+ logger.info(f"Sending processed information to {self.host} {self.queue}...")
xmi = cas.to_xmi()
self.conn.send(self.queue, xmi)
@@ -68,10 +66,10 @@ def send_text(self, text):
self.conn.send(self.queue, text)
def send_stop(self):
- logger.info(f"{time.ctime()} Sending Stop code to {self.host} {self.queue} ...")
+ logger.info(f"Sending Stop code to {self.host} {self.queue} ...")
self.conn.send(self.queue, STOP_MESSAGE)
self.conn.disconnect()
- logger.info(f"{time.ctime()} Disconnected PBJ Sender on self.host self.queue")
+ logger.info(f"Disconnected PBJ Sender on {self.host} {self.queue}.")
def set_host(self, host_name):
self.host = host_name
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
index 99bf635..271b2ee 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pbj_tools/stomp_receiver.py
@@ -1,4 +1,3 @@
-import time
import threading
from threading import Event
import logging
@@ -65,7 +64,7 @@ def __init__(self, pipeline, queue_name, host_name, port_name, password, usernam
# self.__connect_and_subscribe()
def start_receiver(self):
- logger.info(f"{time.ctime()} Starting Stomp Receiver on f{self.source_host} f{self.source_queue} ...")
+ logger.info(f"Starting Stomp Receiver on {self.source_host} {self.source_queue} ...")
# Use a heartbeat of 10 minutes (in milliseconds)
self.conn = stomp.Connection12([(self.source_host, self.source_port)],
keepalive=True, heartbeats=(600000, 600000))
@@ -98,11 +97,11 @@ def set_stop(self, stop):
def stop_receiver(self):
self.stop = True
- logger.info(f"{time.ctime()} Disconnecting Stomp Receiver on f{self.source_host} f{self.source_queue} ...")
+ logger.info(f"Disconnecting Stomp Receiver on {self.source_host} {self.source_queue} ...")
self.conn.disconnect()
- logger.info(f"{time.ctime()} Stomp Receiver disconnected.")
+ logger.info(" Stomp Receiver disconnected.")
self.conn.unsubscribe(destination=self.source_queue, id=self.r_id)
- logger.info(f"{time.ctime()} Stomp Receiver unsubscribed.")
+ logger.info("Stomp Receiver unsubscribed.")
# self.conn.disconnect()
# print(time.ctime((time.time())), "Stomp Receiver disconnected.")
if self.completed:
@@ -110,7 +109,7 @@ def stop_receiver(self):
def on_message(self, frame):
if frame.body == STOP_MESSAGE:
- logger.info(f"{time.ctime()} Received Stop code.")
+ logger.info("Received Stop code.")
# self.stop = True
# time.sleep(3)
self.completed = True
@@ -120,14 +119,14 @@ def on_message(self, frame):
cas = cassis.load_cas_from_xmi(frame.body, self.get_typesystem())
self.pipeline.process(cas)
else:
- logger.error(f"{time.ctime()} Malformed Message: f{frame.body}")
+ logger.error(f"Malformed Message: {frame.body}")
def on_disconnected(self):
if not self.stop:
self.__connect_and_subscribe()
def on_error(self, frame):
- logger.error(f"{time.ctime()} Receiver Error: f{frame.body}")
+ logger.error(f"Receiver Error: {frame.body}")
# Called when an exception is thrown.
def handle_exception(self):
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
index 6b9dd06..1d5f3dc 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/pipeline/pbj_pipeline.py
@@ -1,5 +1,4 @@
import sys
-import time
import traceback
from traceback import TracebackException
from threading import Event
@@ -10,6 +9,13 @@
exit_event = Event()
+# Configure logging here...
+logging.basicConfig(
+ level=logging.INFO,
+ format="%(asctime)s %(name)s - %(levelname)s: %(message)s",
+ datefmt='%m/%d/%Y %I:%M:%S %p'
+)
+
logger = logging.getLogger(__name__)
class PBJPipeline:
@@ -55,7 +61,7 @@ def initialize(self):
if exit_event.is_set():
break
try:
- logger.info(f"{time.ctime()} Initializing f{type(annotator).__name__}... ")
+ logger.info(f"Initializing {type(annotator).__name__}... ")
annotator.initialize()
except Exception as exceptable:
self.handle_exception(annotator, exceptable, True)
@@ -66,7 +72,7 @@ def run(self):
if not self.initialized:
self.initialize()
try:
- logger.info(f"{time.ctime()} Starting f{type(self.c_reader).__name__}...")
+ logger.info(f"Starting {type(self.c_reader).__name__}...")
self.c_reader.start()
except Exception as exceptable:
self.handle_exception(self.c_reader, exceptable)
@@ -81,42 +87,42 @@ def process(self, cas):
if exit_event.is_set():
break
try:
- logger.info(f"{time.ctime()} Running f{type(annotator).__name__}...")
+ logger.info(f"Running {type(annotator).__name__}...")
annotator.process(cas)
except Exception as exceptable:
self.handle_exception(annotator, exceptable)
# At the end of the corpus, call each annotator for cleanup, etc.
def collection_process_complete(self):
- logger.info(f"{time.ctime()} Collection processing complete.")
+ logger.info("Collection processing complete.")
for annotator in self.annotators:
if exit_event.is_set():
break
try:
- logger.info(f"{time.ctime()} Notifying f{type(annotator).__name__} of completion ...")
+ logger.info(f"Notifying {type(annotator).__name__} of completion ...")
annotator.collection_process_complete()
except Exception as exceptable:
self.handle_exception(annotator, exceptable)
- logger.info(f"{time.ctime()} Done.")
+ logger.info("Done.")
exit_event.set()
def handle_exception(self, thrower, exceptable, initializing=False):
- logger.info(f"{time.ctime()} Exception thrown in f{type(thrower).__name__} : f{type(exceptable).__name__} exceptable")
+ logger.info(f"Exception thrown in {type(thrower).__name__} : {type(exceptable).__name__} exceptable")
# print(TracebackException.from_exception(exceptable, limit=-3, capture_locals=True))
traceback.print_exc(limit=3, chain=False)
# Print nice output regarding the exception.
try:
- logger.info(f"{time.ctime()} Notifying f{type(self.c_reader).__name__} of exception ...")
+ logger.info(f"Notifying {type(self.c_reader).__name__} of exception ...")
self.c_reader.handle_exception(thrower, exceptable)
except Exception as exceptable_2:
traceback.print_exc(limit=3, chain=False)
# Distribute handling of exceptions.
for annotator in self.annotators:
try:
- logger.info(f"{time.ctime()} Notifying f{type(annotator).__name__} of exception ...")
+ logger.info(f"Notifying {type(annotator).__name__} of exception ...")
annotator.handle_exception(thrower, exceptable, initializing)
except Exception as exceptable_2:
traceback.print_exc(limit=3, chain=False)
- logger.info(f"{time.ctime()} Done.")
+ logger.info("Done.")
# sys.exit(1)
exit_event.set()
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
index 1ffd6e7..a30206e 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/ctakes_types.py
@@ -160,9 +160,22 @@
LabMention = 'org.apache.ctakes.typesystem.type.textsem.LabMention'
Markable = 'org.apache.ctakes.typesystem.type.textsem.Markable'
CollectionTextRelationIdentifiedAnnotationRelation = 'org.apache.ctakes.typesystem.type.relation.CollectionTextRelationIdentifiedAnnotationRelation'
-# for RT
-DoseModifier = "org.apache.ctakes.typesystem.type.textsem.DoseModifier"
-DosageCountModifier = "org.apache.ctakes.typesystem.type.textsem.DosageCountModifier"
-TotalDosageModifier = "org.apache.ctakes.typesystem.type.textsem.TotalDoseModifier"
-FrequencyModifier = "org.apache.ctakes.typesystem.type.textsem.FrequencyModifier"
-StatusChangeModifier = "org.apache.ctakes.typesystem.type.textsem.StatusChangeModifier"
\ No newline at end of file
+# 03/09/2026
+Patient='org.apache.ctakes.typesystem.type.structured.Patient'
+Corpus='org.apache.ctakes.typesystem.type.structured.Corpus'
+Dose='org.apache.ctakes.typesystem.type.refsem.Dose'
+TotalDose='org.apache.ctakes.typesystem.type.refsem.TotalDose'
+Form='org.apache.ctakes.typesystem.type.refsem.Form'
+Route='org.apache.ctakes.typesystem.type.refsem.Route'
+Frequency='org.apache.ctakes.typesystem.type.refsem.Frequency'
+Duration='org.apache.ctakes.typesystem.type.refsem.Duration'
+StatusChange='org.apache.ctakes.typesystem.type.refsem.StatusChange'
+DoseModifier='org.apache.ctakes.typesystem.type.textsem.DoseModifier'
+TotalDoseModifier='org.apache.ctakes.typesystem.type.textsem.TotalDoseModifier'
+DosageCountModifier='org.apache.ctakes.typesystem.type.textsem.DosageCountModifier'
+FormModifier='org.apache.ctakes.typesystem.type.textsem.FormModifier'
+RouteModifier='org.apache.ctakes.typesystem.type.textsem.RouteModifier'
+FrequencyModifier='org.apache.ctakes.typesystem.type.textsem.FrequencyModifier'
+DurationModifier='org.apache.ctakes.typesystem.type.textsem.DurationModifier'
+StatusChangeModifier='org.apache.ctakes.typesystem.type.textsem.StatusChangeModifier'
+Episode='org.apache.ctakes.typesystem.type.textspan.Episode'
\ No newline at end of file
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
index 6c38893..b04117b 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/ctakes_pbj_py/src/ctakes_pbj/type_system/type_system_loader.py
@@ -1,6 +1,7 @@
import cassis
XMI_INDICATOR = "xmlns:xmi"
-CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/pbj/types/TypeSystem.xml"
+# CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/pbj/types/TypeSystem.xml"
+CTAKES_TYPE_SYSTEM = "resources/org/apache/ctakes/typesystem/types/TypeSystem.xml"
class TypeSystemLoader:
diff --git a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
index b3fc587..56eabf7 100644
--- a/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
+++ b/ctakes-pbj/src/user/resources/org/apache/ctakes/pbj/types/TypeSystem.xml
@@ -271,6 +271,7 @@ Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.SymbolToken</description>
<supertypeName>org.apache.ctakes.typesystem.type.syntax.BaseToken</supertypeName>
</typeDescription>
<typeDescription>
+ <!-- Deprecate. Same as parent type OntologyConcept. CUI = code. TUI = code. Not good anyway, concepts can have >1 TUI. -->
<name>org.apache.ctakes.typesystem.type.refsem.UmlsConcept</name>
<description>Concepts in the Unified Medical Language System (UMLS) Metathesaurus have a concept unique identifier (CUI) and a type unique identifier (TUI, i.e., semantic type) which are curated, normalized codes. For example, "pain" would have a cui=C0030193 and tui=T184.
Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.UmlsConcept</description>
@@ -1040,6 +1041,11 @@ More qualifying information on how the procedure was done.</description>
<rangeTypeName>uima.cas.FSArray</rangeTypeName>
<elementType>org.apache.ctakes.typesystem.type.textsem.IdentifiedAnnotation</elementType>
</featureDescription>
+ <featureDescription>
+ <name>textRepresentation</name>
+ <description>Plain text representation of the Element. Useful when no mentions are associated and normalization cannot be performed.</description>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
<featureDescription>
<name>discoveryTechnique</name>
<description/>
@@ -1087,6 +1093,36 @@ More qualifying information on how the procedure was done.</description>
<description>A normalized form for Time annotations. Inherits from Element, but some fields may be unused.</description>
<supertypeName>org.apache.ctakes.typesystem.type.refsem.Element</supertypeName>
<features>
+ <featureDescription>
+ <name>hour</name>
+ <description/>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>minute</name>
+ <description/>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>second</name>
+ <description/>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>hourValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>minuteValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>secondValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
<featureDescription>
<name>normalizedForm</name>
<description/>
@@ -1114,6 +1150,21 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
+ <featureDescription>
+ <name>dayValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>monthValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>yearValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
</features>
</typeDescription>
<typeDescription>
@@ -1275,7 +1326,7 @@ This instantiates a manages/treats relation which should be marked as conditiona
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.CollectionTextRelation</name>
- <description/>
+ <description>Generic relation between two spans in text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.Relation</supertypeName>
<features>
<featureDescription>
@@ -1362,107 +1413,107 @@ This instantiates a manages/treats relation which should be marked as conditiona
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.AffectsTextRelation</name>
- <description/>
+ <description>Affects type relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.CausesBringsAbout</name>
- <description/>
+ <description>Causes or Brings about relation between two Elements.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.CausesBringsAboutTextRelation</name>
- <description/>
+ <description>Causes or Brings about relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ComplicatesDisrupts</name>
- <description/>
+ <description>Complicates or Disrupts relation between two Elements.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ComplicatesDisruptsTextRelation</name>
- <description/>
+ <description>Complicates or Disrupts relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.Contraindicates</name>
- <description/>
+ <description>Contraindicates relation between two Elements</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ContraindicatesTextRelation</name>
- <description/>
+ <description>Contraindicates relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.Diagnoses</name>
- <description/>
+ <description>Diagnoses relation between two Elements.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.DiagnosesTextRelation</name>
- <description/>
+ <description>Contraindicates relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.Indicates</name>
- <description/>
+ <description>Indicates relation between two Elements</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.IndicatesTextRelation</name>
- <description/>
+ <description>Indicates relation between two spans of text.</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.IsIndicatedFor</name>
- <description/>
+ <description>Is Indicated For relation between two Elements</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.IsIndicatedForTextRelation</name>
- <description/>
+ <description>Is Indicated For relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ManagesTreats</name>
- <description/>
+ <description>Manages or Treats relation between two Elements</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.Prevents</name>
- <description/>
+ <description>Prevents relation between two Elements</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.ElementRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.PreventsTextRelation</name>
- <description/>
+ <description>Prevents relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.DegreeOfTextRelation</name>
- <description/>
+ <description>Degree relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.LocationOfTextRelation</name>
- <description/>
+ <description>Location relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ManagesTreatsTextRelation</name>
- <description/>
+ <description>Manages or Treats relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ManifestationOfTextRelation</name>
- <description/>
+ <description>Manifestation relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.relation.ResultOfTextRelation</name>
- <description/>
+ <description>Result relation between two spans of text</description>
<supertypeName>org.apache.ctakes.typesystem.type.relation.BinaryTextRelation</supertypeName>
</typeDescription>
<typeDescription>
@@ -1485,11 +1536,20 @@ This instantiates a manages/treats relation which should be marked as conditiona
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
- <featureDescription>
+ <featureDescription>
+ <name>birthDateValue</name>
+ <description/>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
<name>deathDate</name>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
+ <featureDescription>
+ <name>deathDateValue</name>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+ </featureDescription>
<featureDescription>
<name>gender</name>
<description/>
@@ -1529,12 +1589,12 @@ This instantiates a manages/treats relation which should be marked as conditiona
<features>
<featureDescription>
<name>noteTypeCode</name>
- <description/>
+ <description>Pathology: PATH, Imaging: IMG, Progress: PROG, (generic) Clinical: NOTE</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
<featureDescription>
<name>noteSubTypeCode</name>
- <description/>
+ <description>AUTOPSY vs. BIOPSY, MRI vs. XRAY, PREOP vs. POSTOP, OBGYN vs. ENT, etc.</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
<featureDescription>
@@ -1567,6 +1627,15 @@ This instantiates a manages/treats relation which should be marked as conditiona
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
+ <!-- Normalized Date and Time -->
+ <featureDescription>
+ <name>sourceCreationDate</name>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Date</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>sourceCreationTime</name>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Time</rangeTypeName>
+ </featureDescription>
<featureDescription>
<name>sourceInstitution</name>
<description/>
@@ -1584,6 +1653,60 @@ This instantiates a manages/treats relation which should be marked as conditiona
</featureDescription>
</features>
</typeDescription>
+ <typeDescription>
+ <name>org.apache.ctakes.typesystem.type.structured.Patient</name>
+ <description>Patient information. Patient information intermixed with general metadata is deprecated.</description>
+ <supertypeName>uima.cas.TOP</supertypeName>
+ <features>
+ <featureDescription>
+ <name>patientIdentifier</name>
+ <description>Represents a text identifier for the patient.</description>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>patientNum</name>
+ <description>patientNum is a simple long. Could be an index in an array or table.</description>
+ <rangeTypeName>uima.cas.Long</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>demographics</name>
+ <description/>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.structured.Demographics</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>documentCount</name>
+ <description>The number of documents for the patient in the corpus.</description>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ </features>
+ </typeDescription>
+ <typeDescription>
+ <name>org.apache.ctakes.typesystem.type.structured.Corpus</name>
+ <description>Information about a corpus containing documents.</description>
+ <supertypeName>uima.cas.TOP</supertypeName>
+ <features>
+ <featureDescription>
+ <name>corpusId</name>
+ <description>Some unique identifier.</description>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>corpusName</name>
+ <description>A name of the corpus, for instance UPMC Melanoma Pathology Notes.</description>
+ <rangeTypeName>uima.cas.String</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>patientCount</name>
+ <description>The number of patients in the corpus.</description>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>documentCount</name>
+ <description>The number of documents in the corpus.</description>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ </features>
+ </typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.structured.Metadata</name>
<description>Structured data that captures information about the document, patient, or context of the clinical text.</description>
@@ -1964,6 +2087,16 @@ This instantiates a manages/treats relation which should be marked as conditiona
<description/>
<rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Time</rangeTypeName>
</featureDescription>
+ <featureDescription>
+ <name>frequency</name>
+ <description/>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Frequency</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
+ <name>duration</name>
+ <description/>
+ <rangeTypeName>org.apache.ctakes.typesystem.type.refsem.Duration</rangeTypeName>
+ </featureDescription>
<featureDescription>
<name>timeClass</name>
<description>DATE, DURATION, QUANTIFIER, PREPOSTEXP, etc.</description>
@@ -2108,7 +2241,7 @@ Equivalent to cTAKES: edu.mayo.bmi.uima.core.type.Properties</description>
</typeDescription>
<typeDescription>
<name>org.apache.ctakes.typesystem.type.structured.DocumentClassification</name>
- <description/>
+ <description>Type of Document containing full text.</description>
<supertypeName>uima.cas.TOP</supertypeName>
<features>
<featureDescription>
@@ -2746,6 +2879,11 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
+ <featureDescription>
+ <name>countValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
</features>
</typeDescription>
<typeDescription>
@@ -2759,7 +2897,12 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
- <featureDescription>
+ <featureDescription>
+ <name>numberValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
<name>unit</name>
<description>the unit of dose measurement</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2777,7 +2920,12 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
- <featureDescription>
+ <featureDescription>
+ <name>numberValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
<name>unit</name>
<description>the unit of dose measurement</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2818,7 +2966,12 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
- <featureDescription>
+ <featureDescription>
+ <name>numberValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
<name>unit</name>
<description>The periodic unit used, e.g day, month, hour, etc.</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
@@ -2835,7 +2988,12 @@ More qualifying information on how the procedure was done.</description>
<description/>
<rangeTypeName>uima.cas.String</rangeTypeName>
</featureDescription>
- <featureDescription>
+ <featureDescription>
+ <name>numberValue</name>
+ <description/>
+ <rangeTypeName>uima.cas.Integer</rangeTypeName>
+ </featureDescription>
+ <featureDescription>
<name>unit</name>
<description>the unit of time measurement. e.g day, month, hour, etc.</description>
<rangeTypeName>uima.cas.String</rangeTypeName>
diff --git a/ctakes-ytex-uima/pom.xml b/ctakes-ytex-uima/pom.xml
index 2500205..f08cba9 100644
--- a/ctakes-ytex-uima/pom.xml
+++ b/ctakes-ytex-uima/pom.xml
@@ -166,26 +166,26 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
- <execution>
- <id>generate-test-config</id>
- <phase>pre-integration-test</phase>
- <goals>
- <goal>run</goal>
- </goals>
- <configuration>
- <target>
- <!-- default to hsql, override via -D -->
- <property name="db.type" value="hsql" />
- <ant antfile="build-setup.xml" dir="${project.basedir}/../ctakes-ytex/scripts" target="test.setup">
- <property name="config.local" value="${project.build.testOutputDirectory}" />
-<!-- <property name="db.type" value="${db.type}" />-->
- <property name="db.type" value="hsql" />
- <property name="ytex.test" value="true" />
- <property name="ctakes.home" value="${project.basedir}/.." />
- </ant>
- </target>
- </configuration>
- </execution>
+<!-- <execution>-->
+<!-- <id>generate-test-config</id>-->
+<!-- <phase>pre-integration-test</phase>-->
+<!-- <goals>-->
+<!-- <goal>run</goal>-->
+<!-- </goals>-->
+<!-- <configuration>-->
+<!-- <target>-->
+<!-- <!– default to hsql, override via -D –>-->
+<!-- <property name="db.type" value="hsql" />-->
+<!-- <ant antfile="build-setup.xml" dir="${project.basedir}/../ctakes-ytex/scripts" target="test.setup">-->
+<!-- <property name="config.local" value="${project.build.testOutputDirectory}" />-->
+<!--<!– <property name="db.type" value="${db.type}" />–>-->
+<!-- <property name="db.type" value="hsql" />-->
+<!-- <property name="ytex.test" value="true" />-->
+<!-- <property name="ctakes.home" value="${project.basedir}/.." />-->
+<!-- </ant>-->
+<!-- </target>-->
+<!-- </configuration>-->
+<!-- </execution> -->
</executions>
</plugin>
<!-- run all tests in the integration test phase -->