Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Регулярные выражения > вывод поисковиком


Автор: gcc 30.12.2009, 01:36
хотел спроcить вопрос по поводу построения поиска

есть
Код
SELECT *,
MATCH (name_co,heading_name_co,keys_co,text_co) AGAINST (? IN BOOLEAN MODE) as REL
FROM content
WHERE MATCH (name_co,heading_name_co,keys_co,text_co) AGAINST (? IN BOOLEAN MODE)
ORDER BY REL 


но text_co выводит очень длинные текст, как обрезать текст, точнее как найти поисковые слова в тексте обрезать и вывести  - 15 симвлов и +15 символов между поисковым словом

короче, сложно сформулировать вопрос, но как обрезать красиво текст и показать его, так как делает google или yandex?

Автор: gcc 30.12.2009, 18:07
т.е. подскажите как это можно обработать, что-то варианты не могу найти..

можно ли весь текст в массив занести через splite? и там порезать и лишнеее выбросить?
должно быть решение, чтобы велосипед не писать?

Автор: gcc 3.1.2010, 19:56
написал, но есть трудности


при поисковой фразе в 5 букв

выполняется около 10 сек .и грузит процессор

Код

|   -> /search/Quantum_Search                                | 6.877156s |
|    -> /search/super_for                                    | 2.057159s |
|     -> /search/search_map                                  | 0.010212s |
|     -> /search/search_map                                  | 0.010496s |
|     -> /search/search_map                                  | 0.010286s |
|     -> /search/search_map                                  | 0.014969s |
|     -> /search/search_map                                  | 0.010115s |
|     -> /search/search_map                                  | 0.010048s |
|     -> /search/search_map                                  | 0.010178s |
|     -> /search/search_map                                  | 0.010616s |
|     -> /search/search_map                                  | 0.130462s |
|     -> /search/search_map                                  | 0.009996s |
|     -> /search/search_map                                  | 0.010842s |
|     -> /search/search_map                                  | 0.010344s |
|     -> /search/search_map                                  | 0.010349s |
|     -> /search/search_map                                  | 0.016976s |
|     -> /search/search_map                                  | 0.011357s |
|     -> /search/search_map                                  | 0.010190s |
|     -> /search/search_map                                  | 0.014694s |
|     -> /search/search_map                                  | 0.040221s |
|     -> /search/search_map                                  | 0.009894s |
........................
........................
|    -> /search/out_hash                                     | 4.781784s |




на странице 10 элементов и кажный медленно выполняется
около | 6.877156s | каждый 

можно ли как-то ускорить или сделать чтобы не грузил процессор?


алгоритм:

есть текст который нашла MySQL и есть поисковые слова

сам текст занимает много где-то 30 000 сиволов (или или меньше пускай 10 000)

нужно найти в каком участке найболее совпадений, и чтобы "короткий участок" вывести пользователю....

нужно поделить этот текст по 25 символов и занести в массив всего получиться около 500 элементов массива

есть модуль которые быстро ищет чем база данных (так говорит автор)  Quantum::Superpositions http://ru.wikipedia.org/wiki/%D0%9A%D0%B2%D0%B0%D0%BD%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D1%81%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D1%8C

http://www.opennet.ru/docs/RUS/perl_obzor/files/quantium.html

по этому каждые слова еще разделить на массив (получиться двух мерный массив)

===

поисковая фраза входит которая входит  $word_all

$content - текст

вывод результат это return $search;

Код

package MyApp::Controller::search;

use strict;
use warnings;
use parent 'Catalyst::Controller';

use Data::Dumper;
use Quantum::Superpositions BINARY => ["CORE::index"];

# ...........................

sub Quantum_Search : Privat {

    my ( $self, $c, $content, $word_all ) = @_;

    my $words;

    @$words = split( / /, $word_all );

    my $word_one;

    $word_one->[0] = $word_all;

    my $hh;

    foreach my $my ( split( / /, $content ) ) {

        if ( $my && $my ne '' ) {
            push @$hh, $my;
        }

    }

    my $max_line = sprintf( '%.f', scalar(@$hh) / 25 );

    my $aa2;

    my $i = 0;

    for ( 0 .. $max_line ) {

        $i = $_ * 25;

        push @{ $aa2->[$_] }, @{$hh}[ $i .. ( $i + 25 ) ];

    }

    my $found = $c->forward( 'super_for', [ $aa2, $words ] );

    my $out;

    %$out = ();

    $out = $c->forward( 'out_hash', [ $found, $out ] );

    my $search = ' ';

    if ( scalar( keys %$out ) == 0 ) {

        $search = ' ... ' . join( ' ', @{ $aa2->[0] } );

    }
    else {

        foreach my $key ( keys %$out ) {

            $search .= ' ... ' . join( ' ', @{ $aa2->[$key] } );

        }

    }

    return $search;

}

sub out_hash : Privat {

    my ( $self, $c, $found, $out ) = @_;

    my @f;

    my $count = 0;

    while (1) {

        $count++;

        @f = $c->model('Sorting')->super_max($found);

        last if ( !@f );

        my ( $it, $ti ) = $f[0] =~ /(\d+).(\d+)/;

        last if ( !$it || $it == 0 );

        $out->{$ti} = $it;

        splice @$found, $ti, 1;

        last if ( $count == 3 );

    }

    return $out;

}

sub super_for : Privat {

    my ( $self, $c, $aa2, $words ) = @_;

    my ( $it, $ti );

    my $found;

    my $co = 0;

    my $tt;

    map {

        my $i = $_;

        $tt = $c->forward( 'search_map', [ $i, $words, $co, $found ] );

        $found->[$co] = $tt;

        $co++;

    } @$aa2;

    return $found;
}

sub search_map : Privat {

    my ( $self, $c, $i, $words, $co, $found ) = @_;

    my $tt;

    for ( 0 .. $words->[-1] ) {

        if ( index( any(@$i), $_ ) >= 0 ) {

            if ( $found->[$co] ) {

                my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                $tt = ( $it + 1 );
                $tt .= '.';
                $tt .= $co;

            }
            else {

                $tt = '1.';
                $tt .= $co;
            }

        }
        else {

            if ( !$found->[$co] ) {
                $tt = '0.';
                $tt .= $co;

            }

        }

    }

    return $tt;

}



вот это eigenstates (Ква́нтовая сце́пленность ( «запу́танность, перепу́танность»)) не захотела работат, это поиск максимального значения в массиве

по этому сделал другой класс:

вызывается - @f = $c->model('Sorting')->super_max( $found ); 

Код

package MyApp::Model::Sorting;

use strict;
use warnings;
use parent qw( Catalyst::Model Class::Accessor );

use Quantum::Superpositions BINARY => ["CORE::index"];

sub super_max  {
  my ( $self, $found) = @_;
  
   my @f = eigenstates( any(@$found) >= all(@$found) );
 
return @f; 

}




при прохождении по массиву кокло 200-500 элементов - медленно
можно ли как-то ускорить или сделать чтобы не грузил процессор?


как это по другому можно сделать?




Автор: gcc 4.1.2010, 03:22
я поменял   if ( index( any(@$i), $_ ) >= 0 ) {

на       if ( $va && $word && $va =~ /$word/i ) {      

+ добавил цикл

оно стало чуть помягче!!!

====

но все равно как-то притормаживает

что еще можно сделать?? я внизу привул окончательный вариант


Код

| /search/index                                              | 5.936440s |
|  -> /search/content_search                                 | 0.002550s |
|  -> /search/search_sql_count                               | 0.008812s |
|  -> /search/search_sql                                     | 0.008155s |
|  -> /search/content_foreach                                | 5.907569s |
|   -> /search/Quantum_Search                                | 0.312052s |
|    -> /search/super_for                                    | 0.011437s |
|    -> /search/out_hash                                     | 0.278090s |
|   -> /search/Quantum_Search                                | 2.475642s |
|    -> /search/super_for                                    | 0.024424s |
|    -> /search/out_hash                                     | 2.435239s |
|   -> /search/Quantum_Search                                | 1.623805s |
|    -> /search/super_for                                    | 0.021452s |
|    -> /search/out_hash                                     | 1.587708s |
|   -> /search/Quantum_Search                                | 1.465901s |
|    -> /search/super_for                                    | 0.025442s |
|    -> /search/out_hash                                     | 1.423291s |




я 5 сек. все занимает

out_hash - это метод в котором ищется самое большое значение массива (цифра) 
my @f = eigenstates( any(@$found) >= all(@$found) );
всего элементов около 200 и оно выполняется 2 сек, это номрально ??




Код

package MyApp::Controller::search;

use strict;
use warnings;
use parent 'Catalyst::Controller';

use Data::Dumper;
use Quantum::Superpositions BINARY => ["CORE::index"];

## ....................

sub Quantum_Search : Privat {

    my ( $self, $c, $content, $word_all ) = @_;

    $content =~ tr/ / /s;

    my $words;

    @$words = split( / /, $word_all );

    my $word_one;

    $word_one->[0] = $word_all;

    my $hh;

    foreach my $my ( split( / /, $content ) ) {

        if ( $my && $my ne '' ) {
            push @$hh, $my;
        }

    }

    my $max_line = sprintf( '%.f', scalar(@$hh) / 25 );

    my $aa2;

    my $i = 0;

    for ( 0 .. $max_line ) {

        $i = $_ * 25;

        push @{ $aa2->[$_] }, @{$hh}[ $i .. ( $i + 25 ) ];

    }

    my $found = $c->forward( 'super_for', [ $aa2, $words ] );

    my $out;

    %$out = ();

    $out = $c->forward( 'out_hash', [ $found, $out ] );

    my $search = ' ';

    if ( scalar( keys %$out ) == 0 ) {

        $search = ' ... ' . join( ' ', @{ $aa2->[0] } );

    }
    else {

        foreach my $key ( keys %$out ) {

            $search .= ' ... ' . join( ' ', @{ $aa2->[$key] } );

        }

    }

    return $search;

}

sub out_hash : Privat {

    my ( $self, $c, $found, $out ) = @_;

    my @f;

    my $count = 0;

    while (1) {

        $count++;

        @f = $c->model('Sorting')->super_max($found);

        last if ( !@f );

        my ( $it, $ti ) = $f[0] =~ /(\d+).(\d+)/;

        last if ( !$it || $it == 0 );

        $out->{$ti} = $it;

        splice @$found, $ti, 1;

        last if ( $count == 3 );

    }

    return $out;

}

sub super_max : Privat {
    my ( $self, $c, $found ) = @_;

    my @f = eigenstates( any(@$found) >= all(@$found) );

    return @f;

}

sub super_for : Privat {

    my ( $self, $c, $aa2, $words ) = @_;

    my ( $it, $ti );

    my $found;

    foreach my $co ( 0 .. scalar(@$aa2) ) {

        foreach my $va ( @{ $aa2->[$co] } ) {

            foreach my $word (@$words) {

                if ( $va && $word && $va =~ /$word/i ) {

                    if ( $found->[$co] ) {

                        my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                        $found->[$co] = ( $it + 1 );
                        $found->[$co] .= '.';
                        $found->[$co] .= $co;

                        #}

                    }
                    else {

                        $found->[$co] = '1.';
                        $found->[$co] .= $co;
                    }

                }
                else {

                    if ( !$found->[$co] ) {

                        $found->[$co] = '0.';
                        $found->[$co] .= $co;

                    }

                }

            }

        }

    }

    return $found;
}

sub search_map : Privat {

    my ( $self, $c, $i, $words, $co, $found ) = @_;

    my $tt;

    foreach my $va (@$i) {

        foreach my $word (@$words) {

            if ( $va && $word && $va =~ /$word/i ) {

                print $co . ' --- ' . $found->[$co] . '\n';

                if ( $found->[$co] ) {

                    my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                    $tt = ( $it + 1 );
                    $tt .= '.';
                    $tt .= $co;

                }
                else {

                    $tt = '1.';
                    $tt .= $co;
                }

            }
            else {

                if ( !$found->[$co] ) {

                    print '22';

                    $tt = '0.';
                    $tt .= $co;

                }

            }

        }

    }

    return $tt;

}

1;





как можно ускорить? тексты скорости я привел вверху в этом сообщении


Автор: gcc 5.1.2010, 06:37
вообщем сделал еще оптимизировал....


вот эта штука index(any(@$i), $_) >= 0

поиск в большой базе, медленно работала, заменил на 

      if ( $va && $word && $va =~ /$word/i ) {      

+ удалил дубликаты там где оно совпало большое количество раз

по поже покажу полный рабочий вариант.....


но вот все таки этот участок кода при большом количестве поисковых фраз выполняется 0.3 сек 


вот этот участок выполняется один раз 0.3с если добавить еще больше текста и поисковых фраз, то можеи быть до 1с, а всего 10 таких надо обработать... (хотя по сокрости сложно сказать, может быть оно и номрально, текст же не можеи быть через вычайно большой и поисковая фараза большим предложением)

НО может быть можно ускорить?

$aa2 - это двух мерный массив 100-500 элементов
@{ $aa2->[$co] }  - массив 25 элементов, "разбитая" строка по кускам
@$words - 1-20 элементов поисковая фраза

Код


sub super_for : Privat {

    my ( $self, $c, $aa2, $words ) = @_;

    my ( $it, $ti );

    my $found;

    foreach my $co ( 0 .. scalar(@$aa2) ) {

        foreach my $va ( @{ $aa2->[$co] } ) {

            foreach my $word (@$words) {

                if ( $va && $word && $va =~ /$word/i ) {

                    if ( $found->[$co] ) {

                       my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                        $found->[$co] = ( $it + 1 );
                        $found->[$co] .= '.';
                        $found->[$co] .= $co;

                    }
                    else {
                        $found->[$co] = '1.';
                        $found->[$co] .= $co;
                    }

                }
                else {

                    if ( !$found->[$co] ) {

                        $found->[$co] = '0.';
                        $found->[$co] .= $co;

                    }

                }

            }

        }

    }

    return $found;

}


Добавлено @ 06:42
вот полностью

Код


sub Quantum_Search : Privat {

    my ( $self, $c, $content, $word_all ) = @_;

    my $max_world = 25;

    my $words;

    $word_all = Encode::encode( 'utf8', $word_all );
    @$words = split( / /, $word_all );

    my $word_one;

    $word_one->[0] = $word_all;

    my $hh;

    foreach my $my ( split( / /, $content ) ) {

        if ( $my && $my ne '' ) {
            push @$hh, $my;
        }

    }

    my $max_line = sprintf( '%.f', scalar(@$hh) / $max_world );

    my $aa2;

    my $i = 0;

    for ( 0 .. $max_line ) {

        $i = $_ * $max_world;

        push @{ $aa2->[$_] }, @{$hh}[ $i .. ( $i + $max_world ) ];

    }

    my $found = $c->forward( 'super_for', [ $aa2, $word_one ] );

    my $out;

    %$out = ();

    $out = $c->forward( 'out_hash', [ $found, $out ] );

    if ( scalar( keys %$out ) < 2 ) {

        $found = $c->forward( 'super_for', [ $aa2, $words ] );

        $out = $c->forward( 'out_hash', [ $found, $out ] );

    }

    my $search = ' ';

    if ( scalar( keys %$out ) == 0 ) {

        $search = ' ... ' . join( ' ', @{ $aa2->[0] } );

    }
    else {

        foreach my $key ( keys %$out ) {

            $search .= ' ... ' . join( ' ', @{ $aa2->[$key] } );

        }

    }

    return $search;

}

sub out_hash : Privat {

    my ( $self, $c, $found, $out ) = @_;

    my @f;

    my $count = 0;

    while (1) {

        $count++;

        @f = $c->model('Sorting')->super_max($found);

        last if ( !@f );

        my ( $it, $ti ) = $f[0] =~ /(\d+).(\d+)/;

        last if ( !$it || $it == 0 );

        $out->{$ti} = $it;

        splice @$found, $ti, 1;

        last if ( $count == 3 );

    }

    return $out;

}

sub super_for : Privat {

    my ( $self, $c, $aa2, $words ) = @_;

    my ( $it, $ti );

    my $found;

    foreach my $co ( 0 .. scalar(@$aa2) ) {

        foreach my $va ( @{ $aa2->[$co] } ) {

            foreach my $word (@$words) {

                if ( $va && $word && $va =~ /$word/i ) {

                    if ( $found->[$co] ) {

                        my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                        $found->[$co] = ( $it + 1 );
                        $found->[$co] .= '.';
                        $found->[$co] .= $co;

                    }
                    else {
                        $found->[$co] = '1.';
                        $found->[$co] .= $co;
                    }

                }
                else {

                    if ( !$found->[$co] ) {

                        $found->[$co] = '0.';
                        $found->[$co] .= $co;

                    }

                }

            }

        }

    }

    return $found;

}




вызывается - @f = $c->model('Sorting')->super_max( $found ); 

Код

package MyApp::Model::Sorting;

use strict;
use warnings;

use parent qw( Catalyst::Model  );
use Class::C3::Adopt::NEXT;
use Quantum::Superpositions;

sub new {
    my ( $self, $c ) = @_;
    $self = $self->next::method(@_);
}

sub super_max {
    my ( $self, $found ) = @_;

    my $super;

    foreach (@$found) {

        my ( $it, $ti ) = $_ =~ /(\d+).(\d+)/;

        next if ( $it == 0 );

        $super->{$it} = $_;

    }

    my $fo;
    @$fo = map +( $super->{$_} ), keys %$super;

    my @f = eigenstates( any(@$fo) >= all(@$fo) );

    return @f;

}

1;


Добавлено через 12 минут и 28 секунд
кстати, тема по-моиму больше относиться к "Общие вопросы", перенесите пожалуйста

Автор: gcc 7.1.2010, 01:38
вот работает

http://www.x0.org.ua/search/content/off/oracle%20%D1%81%D1%80%D0%B0%D0%B7%D1%83


часть
Код





#####
##
## nice find (beautiful search engine)
##
#####

    # $content - весь контент
    # $word_all - поисковая фраза
    # $max_world - число слов на которые должно быть разбита каждая строка

    ## PS все остальное сложно обяснить, все должно быть понятно


    # $ Content - all content
    # $ Word_all - Keyword
    # $ Max_world - the number of words that should be broken down each row

    ## PS explained to all the rest is difficult, all should be clear
    
    

    # $c->model('Quantum')->super_max($found) :

    # find the maximum value in the array
    # 1) the imaginary part of the value contains the array index
    # 1,a) to the imaginary part of this figure matches the index
    # 2) are removed before searching potornye values that occur the 
   # same number of times (the same number of matches)


 

sub Quantum_Search : Privat {

    my ( $self, $c, $content, $word_all ) = @_;

    my $max_world = 25;

    $content =~ tr/ / /s;

    my $words;

    $word_all = Encode::encode( 'utf8', $word_all );
    @$words = split( / /, $word_all );

    my $word_one;

    $word_one->[0] = $word_all;

    my $hh;

    foreach my $my ( split( / /, $content ) ) {

        if ( $my && $my ne '' ) {
            push @$hh, $my;
        }

    }

    my $max_line = sprintf( '%.f', scalar(@$hh) / $max_world );

    my $aa2;

    my $i = 0;

    for ( 0 .. $max_line ) {

        $i = $_ * $max_world;

        $aa2->[$_] = join( " ", @{$hh}[ $i .. ( $i + $max_world ) ] )
          if ( @{$hh}[ $i .. ( $i + $max_world ) ] );

    }

    my $found = $c->forward( 'super_for', [ $aa2, $word_one ] );

    my $out;

    %$out = ();

    $out = $c->forward( 'out_hash', [ $found, $out ] );

    if ( scalar( keys %$out ) < 2 ) {

        $found = $c->forward( 'super_for', [ $aa2, $words ] );

        $out = $c->forward( 'out_hash', [ $found, $out ] );

    }

    my $search = ' ';

    if ( scalar( keys %$out ) == 0 ) {

        $search = ' ... ' . $aa2->[0];

    }
    else {

        foreach my $key ( keys %$out ) {

            $search .= ' ... ' . $aa2->[$key];

        }

    }

    return $search;

}

sub out_hash : Privat {

    my ( $self, $c, $found, $out ) = @_;

    my @f;

    my $count = 0;

    while (1) {

        $count++;

        @f = $c->model('Quantum')->super_max($found);

        last if ( !@f );

        my ( $it, $ti ) = $f[0] =~ /(\d+).(\d+)/;

        last if ( !$it || $it == 0 );

        $out->{$ti} = $it;

        splice @$found, $ti, 1;

        last if ( $count == 3 );

    }

    return $out;

}

sub super_for : Privat {

    my ( $self, $c, $aa2, $words ) = @_;

    my $found;

    foreach my $co ( 0 .. scalar(@$aa2) ) {

        foreach my $word (@$words) {

            if ( $aa2->[$co] && $word && $aa2->[$co] =~ /$word/i ) {

                if ( $found->[$co] ) {

                    my ( $it, $ti ) = $found->[$co] =~ /(\d+).(\d+)/;

                    $found->[$co] = ( $it + 1 );
                    $found->[$co] .= '.';
                    $found->[$co] .= $co;

                }
                else {

                    $found->[$co] = '1.';
                    $found->[$co] .= $co;
                }

            }
            else {

                if ( !$found->[$co] ) {

                    $found->[$co] = '0.';
                    $found->[$co] .= $co;

                }

            }

        }

    }

    return $found;
}














=head1 AUTHOR

Dmitriy

email: rtyug@ukr.net
  www: http://www.x0.org.ua

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;


@f = $c->model('Quantum')->super_max($found);

Код
package MyApp::Model::Quantum;

use strict;
use warnings;
use parent 'Catalyst::Model';

use Quantum::Superpositions;

sub super_max {
    my ( $self, $found ) = @_;

    # find the maximum value in the array
    
    # 1) the imaginary part of the value contains the array index
    # 1,a) to the imaginary part of this figure matches the index
    # 2) are removed before searching potornye values that occur the 
   # same number of times (the same number of matches)

    my $super;

    foreach (@$found) {

    # 1) the imaginary part of the value contains the array index
    # 1,a) to the imaginary part of this figure matches the index
    
        my ( $it, $ti ) = $_ =~ /(\d+).(\d+)/;

        next if ( $it == 0 );
        
    # 2) are removed before searching potornye values that occur 
    # the same number of times (the same number of matches)
        $super->{$it} = $_;

    }

    my $fo;
    @$fo = map +( $super->{$_} ), keys %$super;

     #    # find the maximum value in the array
    my @f = eigenstates( any(@$fo) >= all(@$fo) );

    return @f;

}

=head1 NAME

MyApp::Model::Quantum - Catalyst Model

=head1 DESCRIPTION

Catalyst Model.

=head1 AUTHOR

Dmitriy

email: rtyug@ukr.net
WWW: http://www.x0.org.ua

=head1 LICENSE

This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;






по большой статье в 2 слова:
(довольно быстро)
Код
|  -> /search/search_sql_count                               | 0.004082s |
|  -> /search/search_sql                                     | 0.006884s |
|  -> /search/content_foreach                                | 0.057654s |
|   -> /search/Quantum_Search                                | 0.047120s |
|    -> /search/super_for                                    | 0.002850s |
|    -> /search/out_hash                                     | 0.003985s |
|    -> /search/super_for                                    | 0.004900s |
|    -> /search/out_hash                                     | 0.007530s |




еще можно чтобы

1)  откорректировать поиск если не правильно ввелось слово с раскладкой...
2) и  исправить орфографию на ходу...
Сахор = Сахар
3) и т.д. как у яндекса
 
часть из этого может Sphinx, но другое надо писать...
решил его использовать



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)