DBIx-FullTextSearch

 view release on metacpan or  search on metacpan

lib/DBIx/FullTextSearch/Blob.pm  view on Meta::CPAN

	my ($class, $fts) = @_;
	return bless { 'fts' => $fts }, $class;
}
# Create creates the table(s) according to the parameters
sub _create_tables {
	my ($class, $fts) = @_;
	my $CREATE_DATA = <<EOF;
		create table $fts->{'data_table'} (
			word varchar($fts->{'word_length'}) binary
					default '' not null,
			idx longblob default '' not null,
			primary key (word)
		)
EOF
        my $dbh = $fts->{'dbh'};
	$dbh->do($CREATE_DATA) or return $dbh->errstr;
        push @{$fts->{'created_tables'}}, $fts->{'data_table'};
	return;
}

sub add_document {
	my ($self, $id, $words) = @_;
	my $fts = $self->{'fts'};
	my $dbh = $fts->{'dbh'};
	my $data_table = $fts->{'data_table'};

	my $update_sth = ( defined $self->{'adding_update_sth'}
		? $self->{'adding_update_sth'}
		: $self->{'adding_update_sth'} = $dbh->prepare(
			"update $data_table set idx = concat(idx, ?)
				where word = ?") );

	my @insert_values;

	my $packstring = $DBIx::FullTextSearch::BITS_TO_PACK{$fts->{'doc_id_bits'}}
		. $DBIx::FullTextSearch::BITS_TO_PACK{$fts->{'count_bits'}};
	my $num_words = 0;
	for my $word ( keys %$words ) {
### print STDERR "$word($id) adding\n";
		# here we will want to parametrize the bit size of the
		# data
		my $value = pack $packstring, $id, $words->{$word};
		my $rows = $update_sth->execute($value, $word);
		push @insert_values, $word, $value if $rows == 0;
		$num_words += $words->{$word};
	}

	if(@insert_values){
		my $sql_str = "insert into $data_table values ". join(',', ('(?, ?)') x (@insert_values/2));
		$dbh->do($sql_str,{},@insert_values);
	}

	return $num_words;
}

sub delete_document {
	my $self = shift;
	for my $id (@_) { $self->update_document($id, {}); }
}

sub update_document {
	my ($self, $id, $words) = @_;
	my $fts = $self->{'fts'};
	my $dbh = $fts->{'dbh'};
	my $data_table = $fts->{'data_table'};

	my $insert_sth = ( defined $self->{'insert_sth'}
		? $self->{'insert_sth'}
		: $self->{'insert_sth'} = $dbh->prepare("
			insert into $data_table values (?, ?)") );

        my $update_sth = ( defined $self->{'update_update_sth'}
		? $self->{'update_update_sth'}
		: $self->{'update_update_sth'} =
			$dbh->prepare("update $data_table set idx =
			concat(substring(idx, 1, ?), ?, substring(idx, ?))
					where word = ?") );


	my @insert_values;

	$dbh->do("lock tables $data_table write");

	my $select_sth = $dbh->prepare("select word from $data_table");
	$select_sth->execute;

	my $packstring = $DBIx::FullTextSearch::BITS_TO_PACK{$fts->{'doc_id_bits'}}
		. $DBIx::FullTextSearch::BITS_TO_PACK{$fts->{'count_bits'}};
	my ($packnulls) = pack $packstring, 0, 0;
	my $packlength = length $packnulls;
	my $num_words = 0;
	while (my ($word) = $select_sth->fetchrow_array) {
		my $value = (defined $words->{$word} ?
				pack($packstring, $id, $words->{$word}) : '');

		# the method find_position finds the position of the
		# "record" for document $id with word $word; returned is
		# the position in bytes and yes/no values specifying if
		# the record is already present in the blob; if it is,
		# we need to replace it, otherwise just insert.

		my ($pos, $shift) = $self->find_position($word, $id);
		if (not defined $pos) {
			push @insert_values, $word, $value;
		}
		else {
			my $spos = $pos + 1;	# I'm not sure why this
			$spos += $packlength if $shift;
			$update_sth->execute($pos, $value, $spos, $word);	
		}
		delete $words->{$word};	
		$num_words++ if defined $value;
	}

	for my $word ( keys %$words ) {
		my $value = pack $packstring, $id, $words->{$word};
		push @insert_values, $word, $value;
#		$insert_sth->execute($word, $value);
		$num_words++;
	}



( run in 1.673 second using v1.01-cache-2.11-cpan-7fcb06a456a )