Как оптимизировать MySQL Boolean Полнотекстовый поиск?(Или чем его заменить?) - C # - PullRequest
3 голосов
/ 17 мая 2011

У меня есть таблица, которая содержит приблизительно 22000 строк, и я использовал булевский полнотекстовый поиск, чтобы найти то, что мне интересно. Моя проблема в том, что я создал «чувство динамического поиска», которое состоит из DataGridView что оно обновляется после каждого TextChanged события.Как вы, наверное, поняли, поиск вставленной строки после каждого события занимает много времени.

Что я могу сделать, чтобы улучшить скорость поиска?

Любые предложения приветствуются!

1 Ответ

15 голосов
/ 27 мая 2011

Во-первых, вы должны понимать, что поддержка СУБД для полнотекстовой индексации - это взлом, чтобы заставить технологию, разработанную для обеспечения эффективного доступа к структурированным данным, иметь дело с неструктурированным текстом.(Да, это всего лишь мое мнение. При необходимости я могу защитить его, поскольку я прекрасно понимаю обе технологии.;)

Итак, что можно сделать для повышения эффективности поиска?

Первый вариант - «Лучший инструмент для выполнения задачи»

Лучший способ обработки полнотекстового поиска в совокупности документов - это технология, специально разработанная для этого, например, SOLR (Lucene) от Apache или Sphinx от err, Sphinx.

По причинам, которые станут понятны ниже, я настоятельно рекомендую этот подход.

Вариант второй- Предварительная загрузка результатов

При построении текстовых поисковых решений обычный подход заключается в индексации всех документов в единый поисковый индекс, и, хотя это может быть наиболее целесообразным, это не единственный подход.

Предполагая, что то, что вы ищете, может быть легко определено количественно в виде набора известных правил, вы можете предложить более "управляемый" стиль поиска, чем просто неквалифицированный полнотекст.Под этим я подразумеваю, что если ваше приложение может извлечь выгоду из наведения пользователей на результаты, вы можете предварительно загрузить различные наборы результатов, основанные на известном наборе правил, в их собственные таблицы и, таким образом, уменьшить объем данных, подлежащих поиску.

Если вы ожидаете, что большинство ваших пользователей получат пользу от известного набора поисковых терминов в известном порядке, вы можете создать свой пользовательский интерфейс поиска, чтобы отдавать предпочтение этим терминам.пользователи ищут различные автомобили, вы можете предлагать предопределенные поиски, основанные на модели, году, состоянии и т. д. Ваш пользовательский интерфейс поиска будет создан в виде серии выпадающих меню, чтобы «направлять» пользователей к конкретным результатам.

Или, если большинство поисков будет посвящено определенной основной теме (скажем, «автомобили»), вы можете заранее определить таблицу только тех записей, которые вы ранее определили как относящиеся к автомобилям.

Оба эти подходауменьшит количество записей, которые нужно искать, и, следовательно, увеличит время отклика.

Вариант третий - «Сверни свое»

Если вы не можете интегрировать технологию внешнего поиска в свой проект и предварительная загрузка не выполняетсяЭто не вариант, есть еще способы значительно улучшить время ответа на поисковый запрос, но они отличаютсяв зависимости от того, что вам нужно сделать, и от того, как вы ожидаете, что будут выполняться поиски.

Если вы ожидаете, что пользователи будут выполнять поиск с использованием отдельных ключевых слов или фраз и логических отношений между ними, вы можете подумать о создании своего собственного 'перевернутый индекс 'вашего корпуса.(Это то, что MySQL Boolean Full-Text Search уже делает, но выполнение этого самостоятельно позволяет лучше контролировать скорость и точность поиска.)

Чтобы создать инвертированный индекс из существующих данных:

Шаг 1. Создайте три таблицы

    // dict - a dictionary containing one row per unique word in corpus  
    create table dict (    
      id int primary key,  
      word varchar  
    )

    // invert - an inverted_index to map words to records in corpus  
    create table invert (    
      id int primary key,  
      rec_id int,  
      word_id int  
    )

    // stopwords - to contain words to ignore when indexing (like a, an, the, etc)
    create table stopwords ( 
      id int primary key,  
      word varchar  
    )

Примечание. Это всего лишь эскиз.При создании этих таблиц вы захотите добавить индексы, ограничения и т. Д.

Таблица стоп-слов используется для уменьшения размера вашего индекса до тех слов, которые важны для ожидаемых пользователей.запросы.Например, редко бывает полезно индексировать английские статьи, такие как «a», «an», «the», поскольку они не дают полезного значения для поиска по ключевым словам.

Как правило, вам потребуется список стоп-слов , специально созданный для нужд вашего приложения.Если вы никогда не ожидаете, что пользователи будут включать термины «красный», «белый» или «синий» в свои запросы, или если эти термины присутствуют в каждой доступной для поиска записи, вы можете добавить их в свой список стоп-слов.

См. Примечание в конце этого сообщения для получения инструкций по использованию собственного списка стоп-слов в MySQL.

См. Также:

Шаг 2. Построить перевернутый индекс

Чтобы создать инвертированный индекс из существующих записей, вам нужно (псевдокод):

    foreach( word(w) in record(r) ) {
      if(w is not in stopwords) {
        if( w does not exist in dictionary) {
          insert w to dictionary at w.id
        }
        insert (r.id, w.id) into inverted_index
      }
    }
Подробнее о стоп-словах:

Вместо использования определенного списка стоп-слов, тест if (w не в стоп-словах) может принимать другие решения либо вместо, либо в качестве дополнения к вашему списку недопустимых слов.

Ваше приложение может пожелать отфильтровать все слова длиной менее 4 символов или только в включить слова из предопределенного набора.

Создавая собственный инвертированный индекс, вы получаете гораздо больший и более точный контроль над поиском.

Шаг 3. Запрос инвертированного индекса с использованием SQL

Этот шаг действительно зависит от того, как вы ожидаете, что запросы будут отправлены в ваш индекс.

Если запросы должны быть «жестко запрограммированы», вы можете просто создать оператор выбора самостоятельно или, если вам нужно поддерживать введенные пользователем запросы, вам нужно будет преобразовать любой язык запросов, который вы выберете, в оператор SQL (обычно сделано с помощью простого парсера).

Предполагая, что вы хотите получить все документы, соответствующие логическому запросу '(слово1 И слово2) ИЛИ слово3', возможный подход может быть следующим:

CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS 
    ( SELECT rec_id, COUNT(rec_id) AS count 
      FROM invert AS I, dict AS D 
      WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2') 
      GROUP BY I.rec_id 
      HAVING count=2
    ) 
    UNION (
      SELECT rec_id, 1 AS count 
      FROM invert AS I, dict AS D
      WHERE I.word_id=D.id AND D.word='word3'
    );

SELECT DISTINCT rec_id FROM temp_results;

DROP TABLE temp_results;

ПРИМЕЧАНИЕ: Это всего лишь первый проход с макушки головы. Я уверен, что есть более эффективные способы преобразования логического выражения запроса в эффективный оператор SQL, и приветствую любые предложения по улучшению.

Чтобы искать фразы, вам нужно добавить поле к инвертированному индексу, чтобы представить позицию, в которой слово появилось в его записи, и включить его в ваш SELECT.

И, наконец, вам нужно будет обновить инвертированный индекс при добавлении новых записей или удалении старых.

Последнее слово

«Полнотекстовый поиск» относится к очень большой области исследований, известной как «Поиск информации» или IR, и существует множество книг по этому вопросу, включая

Проверьте Amazon для получения дополнительной информации.

Примечания

Как использовать собственный список стоп-слов в MySQL

Чтобы использовать свой собственный список стоп-слов в MySQL:

  1. Создайте собственный список стоп-слов, по одному слову в строке, и сохраните его в известном месте на вашем сервере, например: /usr/local/lib/IR/stopwords.txt
  2. Отредактируйте my.cnf, чтобы добавить или обновить следующие строки:
        [mysqld]  
        ft_min_word_len=1    
        ft_max_word_len=40  
        ft_stopword_file=/usr/local/lib/IR/stopwords.txt
    

    , который установит минимальную и максимальную длину юридических слов в 1 и 40, соответственно, и сообщите mysqld, где найти ваш пользовательский список стоп-слов.

    (Примечание: по умолчанию ft_max_word_len составляет 84, что я считаю довольно чрезмерным и может привести к тому, что серии строк, которые не являются реальными словами, будут проиндексированы.)

  3. Перезапустить mysqld
  4. Удалить и заново создать все полнотекстовые индексы
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...