This doesn't come with an elaborate test suite, but it does pretty much everything that does in a few dozen lines of Perl. https://github.com/neilk/misc/blob/master/randline I've had this script (or versions of it) around for more than a decade. I didn't know the technique had a name.
it was an example in the original camel book. [edit: i was going to delete this, but since you replied i'll leave it - it does appear (too?) in the camel book, on p 246 of my copy, but like you say, it's for a single line. hadn't opened that book in years, took me some time to find it...]
Dimsum is like head or tail, but pulls randomly from the entire file or stream
21–30 of 31 posts
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#22Earlier quoted context omitted.
I wonder if the implementation of shuf would handle very large input efficiently? Reservoir sampling wouldn't need to keep the whole input in memory, which could be an advantage. But I don't know how shuf works.
Doesn't look like it. I just tried running "yes | shuf -n 1" (using the latest version of GNU coreutils, 8.20) and its memory consumption increased steadily until I killed it. It seems like this would be a really useful improvement, and I'm surprised that it doesn't already seem to have been requested on the coreutils issue tracker.
In my hands, `top` shows resident memory increasing steadily too....
It is perhaps more instructive to compare output from, for example
seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif --massif-out-file=massif.dimsum.100000.out.%p dimsum -n 1
with
seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif --massif-out-file=massif.shuf.100000.out.%p shuf -n 1
in my hands, shuf is faster and uses less memory for this task.
How about you?
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#23Earlier quoted context omitted.
Maybe I'm overlooking something obvious but wouldn't piping through awk 'rand()<.1{print}' give a decent streaming random sample of roughly 10% of input?
Reservoir sampling allows you to return a specific number of samples regardless of the size of the input rather than a specific fraction of samples (which is what your awk script does).
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#24Earlier quoted context omitted.
Doesn't look like it. I just tried running "yes | shuf -n 1" (using the latest version of GNU coreutils, 8.20) and its memory consumption increased steadily until I killed it. It seems like this would be a really useful improvement, and I'm surprised that it doesn't already seem to have been requested on the coreutils issue tracker.
did you try "yes | dimsum -n 1"? In my hands, `top` shows resident memory increasing steadily too.... It is perhaps more instructive to compare output from, for example seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif --massif-out-file=massif.dimsum.100000.out.%p dimsum -n 1 with seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif…
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#25This doesn't come with an elaborate test suite, but it does pretty much everything that does in a few dozen lines of Perl. https://github.com/neilk/misc/blob/master/randline I've had this script (or versions of it) around for more than a decade. I didn't know the technique had a name.
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#26Earlier quoted context omitted.
I wonder if the implementation of shuf would handle very large input efficiently? Reservoir sampling wouldn't need to keep the whole input in memory, which could be an advantage. But I don't know how shuf works.
Doesn't look like it. I just tried running "yes | shuf -n 1" (using the latest version of GNU coreutils, 8.20) and its memory consumption increased steadily until I killed it. It seems like this would be a really useful improvement, and I'm surprised that it doesn't already seem to have been requested on the coreutils issue tracker.
So, let's pursue this: http://lists.gnu.org/archive/html/coreutils/2012-11/msg00079...
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#27Earlier quoted context omitted.
did you try "yes | dimsum -n 1"? In my hands, `top` shows resident memory increasing steadily too.... It is perhaps more instructive to compare output from, for example seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif --massif-out-file=massif.dimsum.100000.out.%p dimsum -n 1 with seq 1 1000000 | valgrind --time-unit=B --pages-as-heap=yes --trace-children=yes --tool=massif…
sigh, memory leak. It's fixed in github. When camilo is around I'll get him to update the gem
Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#28Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#29uses reservoir sampling - http://en.wikipedia.org/wiki/Reservoir_sampling (so it presumably consumes the entire stream before giving any results; any alternative i can think of would not be "really random" unless you knew the length of the stream in advance).
Maybe I'm overlooking something obvious but wouldn't piping through awk 'rand()<.1{print}' give a decent streaming random sample of roughly 10% of input?
dmesg | gawk -f reservoir-sample.awk k=5 record_separator='==='
#!/usr/bin/gawk -f
### reservoir-sample.awk
###
### Sample k random lines from a stream, without knowing the size of the stream.
###
### (Tomer Altman)
### Parameters: (set from command-line)
##
## k: number of lines to sample
## record_separator: string used to separate iterations of the sample in stdout.
## Define a function for returning a number between 1 and n:
function random_int (n) { return 1 + int(rand() * n) }
## Initialize the PRNG seed:
BEGIN { srand() }
## For the first k lines, initialize the sample array:
NR k && (current_random_int = random_int(NR)) Re: Dimsum is like head or tail, but pulls randomly from the entire file or stream
#30I really don't like how this behaves for populating the array initially, and how it behaves for small inputs... $ seq 15 | dimsum -n 10 14 12 3 4 5 6 7 8 9 10