Imported Arrow strings lose nulls when exported in nonzero-offset record batches
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 3/5
- Temps estimé
- Une demi-journée
- Accessibilité débutants
- 66/100
Piste de recherche
The bug is in the null-count loop of ArrowStringDataFrameColumn.GetNullCount in src/Microsoft.Data.Analysis/DataFrameColumns/ArrowStringDataFrameColumn.cs, which uses i < numberOfRows where it should scan from startIndex to startIndex + numberOfRows. Check the same pattern in PrimitiveDataFrameColumn<T>.GetNullCount. Done when a small unit test with a nonzero-offset slice (not the multi-GB repro) shows the correct NullCount and IsNull for the final row.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Description
An Arrow record imported with DataFrame.FromArrowRecordBatch() can export a null string as a valid empty string when ToArrowRecordBatches() divides the DataFrame into multiple batches.
Reproduced on Microsoft.Data.Analysis 0.23.0, Apache.Arrow 14.0.2, Windows x64, .NET 10.
Reproduction
Create a console app, add Microsoft.Data.Analysis version 0.23.0, and run:
using System;
using System.Linq;
using Apache.Arrow;
using Microsoft.Data.Analysis;
const int rows = 268_304_384;
var builder = new StringArray.Builder().Reserve(rows);
builder.Append("a");
builder.AppendRange(Enumerable.Repeat("", rows - 2));
builder.AppendNull();
var input = new RecordBatch.Builder()
.Append("strings", true, builder.Build())
.Build();
var frame = DataFrame.FromArrowRecordBatch(input);
var numbers = new Int64DataFrameColumn("numbers");
numbers.AppendMany(42, rows);
frame.Columns.Add(numbers);
Console.WriteLine($"Imported rows={frame.Rows.Count}; NullCount={frame.Columns["strings"].NullCount}; final string is null={frame[rows - 1, 0] is null}");
int index = 0;
foreach (var batch in frame.ToArrowRecordBatches())
{
var strings = batch.Arrays.OfType<StringArray>().Last();
Console.WriteLine($"Batch {index++}: rows={batch.Length}; last string array length={strings.Length}; NullCount={strings.NullCount}");
if (strings.Length == 1)
Console.WriteLine($"Final exported string={(strings.GetString(0) is { } value ? $"\"{value}\"" : "null")}; IsNull={strings.IsNull(0)}");
}
This deliberately large input needs several GB of RAM. The numeric column naturally occupies two buffers and forces two record batches. The strings remain in one buffer; their final null is exported as a nonzero-offset, one-row slice. A small, single-batch input would not reach the faulty loop bounds.
Actual output
Imported rows=268304384; NullCount=1; final string is null=True
Batch 0: rows=268304383; last string array length=268304383; NullCount=0
Batch 1: rows=1; last string array length=1; NullCount=0
Final exported string=""; IsNull=False
Expected behavior
The final string array should have NullCount == 1, IsNull(0) == true, and GetString(0) == null.
The repro selects the last string array because there is a separate bug where ToArrowRecordBatches() includes previous batches' arrays in later batches (https://github.com/dotnet/machinelearning/issues/7799). This does not cause the newly exported string array's incorrect null metadata.
Cause
ArrowStringDataFrameColumn.GetNullCount loops with i < numberOfRows, treating a row count as an exclusive end index. It should scan [startIndex, startIndex + numberOfRows).
For the final batch, startIndex == 268304383 and numberOfRows == 1, so no validity bits are checked and the null count is incorrectly zero. PrimitiveDataFrameColumn<T>.GetNullCount contains the same loop-bound pattern and should also be considered when fixing this.
- Langage dominant
- C#
- Étoiles
- 9.4k
- Forks
- 2k
- Merge moyen
- 2 j 18 h
- PR mergées (30 j)
- 64
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de dotnet/machinelearning
-
area-Native untriaged
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
dotnet/machinelearning#7837 ·
Les mainteneurs répondent en général sous 1 jour
-
area-TensorFlow untriaged
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
dotnet/machinelearning#7836 ·
Les mainteneurs répondent en général sous 1 jour
-
ToArrowRecordBatches accumulates arrays from previous batches, producing invalid record batchesOuvertearea-DataFrame bug untriaged
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
dotnet/machinelearning#7799 ·
Les mainteneurs répondent en général sous 1 jour
-
LlamaTokenizer encodes some runs of repeated characters differently from SentencePiecePeut-être pris @Laurianti l’a pris il y a 42 jours. Ouvertearea-Tokenizers untriaged
Difficulté 2/5 1-3 heures Accessibilité débutants 88/100
dotnet/machinelearning#7751 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
BertTokenizer merges words separated only by `\n`, `\t` or `\r`Peut-être pris @Laurianti l’a pris il y a 23 jours. Ouvertearea-Tokenizers green
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
dotnet/machinelearning#7724 · 3 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de dotnet/machinelearning
Issues similaires
-
bug emitter:client:csharp
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
microsoft/typespec#12572 · 1 commentaire · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
needs-area-label
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
Les mainteneurs répondent en général sous 2 jours
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabledOuvertebug
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
area-networking
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
dotnet/aspnetcore#70545 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 87/100
Les mainteneurs répondent en général sous 1 jour