Kendi Knime Eklentinizi Oluşturma Rehberi: Node İşlevinin Kodlanması [3. Bölüm]
Merhaba, Kendi Knime Eklentinizi Oluşturma Rehberi serimin son bölümüne ulaştık. Daha önceki bölümlerde geliştirme ortamının hazırlanmasından ve geliştirmekte olduğumuz nodun arayüzünü oluşturmaktan bahsetmiştik. Bu bölümde ise oluşturduğumuz nodun işlevini kodlayacağız.
Bir önceki bölümden hatırlayacağınız gibi iki sütunda yer alan bir ve sıfır değerleri arasında “VE”, “VEYA” mantıksal işlemlerini yapabilen ve sonuçlarını üçüncü bir sütuna yazabilen bir node oluşturuyoruz. Başlangıç olarak knime.core kütüphanesi ile tablo yapılarından ve tablolar üzerinde satır sütun işlemlerinin nasıl yapıldığından bahsedelim.
Knime’da tablolar BufferedDataTable tipinde tutuluyor. Şekil-1’de görüldüğü gibi bu tablolar satırlardan (DataRow), satırlar da hücrelerden (DataCell) oluşuyor.
Tablolar içerisindeki sütun sayısı, sütun isimleri ve sütun veri tipleri gibi bilgiler ise DataTableSpec içerisinde DataColumnSpec tipinde tutuluyor. Bu bilgilere aşağıdaki gibi ulaşabiliyoruz:
// Burada inData[0] nodun sıfırıncı portuna gönderdiğimiz tablo anlamında. BufferedDataTable inputTable = inData[0]; DataTableSpec inputTableSpec = inputTable.getDataTableSpec(); // Sütun sayısı için: int numberOfColumns = inputTableSpec.getNumColumns(); System.out.println(numberOfColumns); // Sıfırıncı sütunun bilgilerini almak için: int columnNumber = 0; DataColumnSpec columnSpec = inputTableSpec.getColumnSpec(columnNumber); // Sıfırıncı sütunun adını öğrenmek için: String columnName = columnSpec.getName(); System.out.println(columnName); // Sıfırıncı sütunun veri tipini öğrenmek için: DataType dataType = columnSpec.getType().getName(); System.out.println(dataType);
Bir tablonun satır sayısını ise doğrudan BufferedDataTable içerisinden öğrenebiliyoruz:
rowCount = inputTable.getRowCount(); System.out.println(rowCount);
Satır ve sütun işlemleri ise birbirinden biraz farklı gerçekleştiriliyor. Eğer bir tabloya satır eklenecekse BufferedDataTable içerisindeki BufferedDataContainer’a doğrudan yeni satır ekleyebiliyoruz. Fakat Yeni bir sütun eklemek için tabloyu baştan oluşturmamız gerekiyor. Çünkü satır objesi (DataRow) varken sütun objesi bulunmamakta bunun yerine satır objeleri içerisinde hücreler (DataCell) bulunmakta. Yeni bir sütun eklemek istediğimizde her bir satır objesinin içerisinde tuttuğu hücre sayısını artırıp yeni hücrelerin tipini ve ismini belirlememiz gerekiyor. Bir BufferedDataContainer objesinin içerisindeki satırların alacağı hücre sayısını değiştirmek için de DataTableSpec objesini güncellememiz gerekiyor. Çünkü sütun isimlerini burada belirtiyoruz.
Bu güncellemeyi yapmadan önce kullanıcıdan istediğimiz girdilere aşağıdaki şekilde ulaşmamız gerek:
// Tablo bilgilerini tutan objeyi aşağıdaki şekilde alıyoruz: DataTableSpec inputTableSpec = inputTable.getDataTableSpec(); // Burada kullanıcıdan istediğimiz her girdiyi değişkenlere kaydediyoruz: String logicGateString = m_logicGateSettings.getStringValue(); String inputAString = m_inputASettings.getColumnName(); String inputBString = m_inputBSettings.getColumnName(); // Hücreleri sütun isimleriyle değil de hücre indeksleriyle yani sütun indeksleriyle çağırmamız gerektiğinden hücre indekslerini aşağıdaki gibi alıyoruz: int inputAColumnIndex = inputTableSpec.findColumnIndex(inputAString); int inputBColumnIndex = inputTableSpec.findColumnIndex(inputBString);
Kullanıcıdan istediğimiz bilgilere eriştiğimize göre artık çıktı olarak vereceğimiz tabloyu oluşturmaya başlayabiliriz. Bunun için daha önce belirttiğim gibi yeni DataTableSpec objemizi oluşturalım:
// DataTableSpec objesi DataColumnSpec objelerinden oluştuğu için her bir sütunun DataColumnSpec objelerini tutabileceğimiz bir diziye ihtiyacımız var: List<DataColumnSpec> newColumnSpecs = new ArrayList<>(); // Şimdi aşağıdaki döngü ile girdi tablosundaki DataColumnSpec objelerini aynen alıyoruz: for (int i = 0; i < inputTableSpec.getNumColumns(); i++) { DataColumnSpec columnSpec = inputTableSpec.getColumnSpec(i); String newName = columnSpec.getName(); DataType newDataType = columnSpec.getType(); DataColumnSpecCreator specCreator = new DataColumnSpecCreator(newName, newDataType); newColumnSpecs.add(specCreator.createSpec()); } // Yeni ekleyeceğimiz sütun için de aşağıdaki gibi yeni bir DataColumnSpec oluşturuyoruz: String newName = inputAString + "_" + logicGateString + "_" + inputBString; DataType newDataType = IntCellFactory.TYPE; DataColumnSpecCreator specCreator = new DataColumnSpecCreator(newName, newDataType); newColumnSpecs.add(specCreator.createSpec()); // Artık yeni tablomuzun DataTableSpec objesini aşağıdaki gibi oluşturabiliriz: DataColumnSpec[] newColumnSpecsArray = newColumnSpecs.toArray(new DataColumnSpec[newColumnSpecs.size()]); DataTableSpec outputSpec = new DataTableSpec(newColumnSpecsArray);
Satırları eklemek için şimdi de bir BufferedDataContainer objesine ihtiyacımız var. DataTableSpec objemizi oluşturduğumuz için bunu da aşağıdaki gibi kolayca oluşturabiliyoruz:
BufferedDataContainer container = exec.createDataContainer(outputSpec);
Artık oluşturduğumu BufferedDataContainer içerisine verimizi aşağıdaki şekilde basabiliriz:
// Yeni tablonun satırlarına erişebilmek için iterator metodunu kullanıyoruz: CloseableRowIterator rowIterator = inputTable.iterator(); int currentRowCounter = 0; while (rowIterator.hasNext()) { // Bir sonraki satıra geçmek için next metodunu kullanıyoruz: DataRow currentRow = rowIterator.next(); int numberOfCells = currentRow.getNumCells(); List<DataCell> cells = new ArrayList<>(); for (int i = 0; i < numberOfCells; i++) { DataCell cell = currentRow.getCell(i); cells.add(cell); } int inputAValue = Integer.parseInt(currentRow.getCell(inputAColumnIndex).toString()); int inputBValue = Integer.parseInt(currentRow.getCell(inputBColumnIndex).toString()); int outputValue = 0; if (logicGateString == "AND") { if ((inputAValue == 1) && (inputBValue == 1)) { outputValue = 1; } else if ((inputAValue == 1) && (inputBValue == 0)) { outputValue = 0; } else if ((inputAValue == 0) && (inputBValue == 0)) { outputValue = 0; } else if ((inputAValue == 0) && (inputBValue == 1)) { outputValue = 0; } } else if (logicGateString == "OR") { if ((inputAValue == 1) && (inputBValue == 1)) { outputValue = 1; } else if ((inputAValue == 1) && (inputBValue == 0)) { outputValue = 1; } else if ((inputAValue == 0) && (inputBValue == 0)) { outputValue = 0; } else if ((inputAValue == 0) && (inputBValue == 1)) { outputValue = 1; } } // Yeni hücreleri satırlara ekliyoruz: DataCell outputCell = IntCellFactory.create(outputValue); cells.add(outputCell); DataRow row = new DefaultRow(currentRow.getKey(), cells); // Oluşturduğumuz yeni satırları da container'a ekliyoruz: container.addRowToTable(row); currentRowCounter++; exec.checkCanceled(); exec.setProgress(currentRowCounter / (double) inputTable.size(), "Formatting row " + currentRowCounter); } container.close();
Sonuç olarak elde ettiğimiz BufferedDataContainer objesini kullanarak aşağıdaki gibi çıktı olarak göndereceğimiz BufferedDataTable objesini oluşturuyoruz:
BufferedDataTable out = container.getTable();
Buraya kadar anlattığım adımları takip ettiyseniz artık nodumuz kullanıma hazır. Değişiklik yaptığımız scriptlerin son hallerine bu linkten ulaşabilirsiniz. Oluşturduğumuz nodu test etmek için projeyi çalıştırıp aşağıdaki (Şekil-2) gibi bir akış oluşturalım:
Burada Table Creator nodu ile aşağıdaki şekilde (Şekil-3) örnek bir tablo oluşturalım:
Kendi hazırladığımız LogicGate nodunu da aşağıdaki (Şekil-4) gibi ayarlayalım:
Bu iş akışını çalıştırıp nodumuzun çıktısına baktığımızda aşağıdaki (Şekil-5) tabloyu göreceğiz:
Gördüğünüz gibi istediğimiz sonuca ulaştık. Artık kendi ihtiyaç duyduğunuz eklentileri oluşturup Knime’ın sınırlarını dilediğinizce aşabilirsiniz. Knime’ın geliştirici rehberlerinden faydalanarak oluşturacağınız eklentileri topluluk ile paylaşabilirsiniz.
Kendi Knime eklentilerinizi nasıl oluşturabileceğinizi anlattığım serimin sonuna geldik. Umarım faydalı bir yazı dizisi olmuştur.