Динамический поиск и отображение

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

Мое требование следующее:

  • Мне нужна оптимизированная функция поиска: я поставляю эту функцию поиска списком (одним или несколькими) частично заполненными (или полными) словами, разделенными пробелами.
  • Затем функция находит все документы, содержащие слова, начинающиеся с первого слова или равные ему, затем выполняет поиск в этих найденных документах таким же образом, используя второе слово и т. д., В конце которого она возвращает список, содержащий фактические слова, найденные связанными. с документами (название и местонахождение), содержащими их, для полного списка слов.
  • Документы должны содержать все слов в списке.
  • Я хочу использовать эту функцию для выполнения поиска по мере ввода, чтобы я мог отображать и обновлять результаты в виде древовидной структуры в режиме реального времени.

Возможный подход к решению, которое я придумал, следующий: Я создаю базу данных (скорее всего, используя mysql) с тремя таблицами: «Документы», «Слова» и «Word_Docs».

  • «Документы» будут содержать (idDoc, имя, местонахождение) всех документов.
  • «Слова» будут иметь (idWord, Word) и будут списком уникальных слов из всех документов (конкретное слово появляется только один раз).
  • Word_Docs будет иметь (idWord, idDoc) и будет списком уникальных комбинаций идентификаторов для каждого слова и документа, в котором оно появляется.

Затем функция вызывается с содержимым поля редактирования при каждом нажатии клавиши (кроме пробела):

  • строка токенизирована
  • (здесь мои колеса немного крутятся): я уверен, что можно создать один оператор SQL, чтобы вернуть требуемый набор данных: (actual_words, doc_name, doc_location); (Я не любитель SQL) или последовательность вызовов для каждого токена и анализ неповторяющихся idDocs?
  • этот набор данных (/ list / array) затем возвращается

Затем отображается возвращенное содержимое списка:

например: вызывается с помощью: "seq sta cod" отображает:

sequence - start - code - Counting Sequences [file://docs/sample/con_seq.txt]
         - stop - code - Counting Sequences [file://docs/sample/con_seq.txt]
sequential - statement - code - SQL intro [file://somewhere/sql_intro.doc]

(и так далее)

Это оптимальный способ сделать это? Функция должна быть быстрой или ее следует вызывать только при попадании в пробел? Должен ли он предлагать завершение слов? (Есть слова в базе данных) По крайней мере, это предотвратит бесполезные вызовы функции для слов, которых не существует. Если слово-завершение: как это будет реализовано?

(Может быть, SO также может использовать этот тип поискового решения для просмотра тегов? (В правом верхнем углу главной страницы))

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
559
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Не уверен в синтаксисе (это синтаксис sql server), но:

-- N is the number of elements in the list

SELECT idDoc, COUNT(1)
FROM Word_Docs wd INNER JOIN Words w on w.idWord = wd.idWord
WHERE w.Word IN ('word1', ..., 'wordN')
GROUP BY wd.idDoc
HAVING COUNT(1) = N

То есть без использования лайков. С подобными дела обстоят НАМНОГО сложнее.

Самый быстрый способ - это вообще не использовать базу данных, поскольку, если вы выполняете поиск вручную с оптимизированными данными, вы можете легко превзойти производительность выборочного поиска. Самый быстрый способ, при условии, что документы не меняются очень часто, - это создать индексные файлы и использовать их для поиска ключевых слов. Индексный файл создается следующим образом:

  1. Найдите все уникальные слова в текстовом файле. Это разбивает текстовый файл пробелами на слова и добавляет каждое слово в список, если оно еще не найдено в этом списке.

  2. Возьмите все найденные слова и отсортируйте их в алфавитном порядке; Самый быстрый способ сделать это - использовать Трехсторонняя Radix QuickSort. Этот алгоритм трудно превзойти по производительности при сортировке строк.

  3. Запишите отсортированный список на диск, по одному слову в строке.

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

В качестве альтернативы вы можете объединить шаг (1) и шаг (2) в один шаг. Если вы используете InsertionSort (который использует двоичный поиск, чтобы найти правильную позицию вставки для вставки нового элемента в уже отсортированный список), у вас не только есть быстрый алгоритм, чтобы узнать, есть ли слово уже в списке или нет, на случай это не так, вы сразу получаете правильную позицию для вставки, и если вы всегда вставляете новые, такие как это, у вас автоматически будет отсортированный список, когда вы дойдете до шага (3).

Проблема в том, что вам нужно обновлять индекс всякий раз, когда документ изменяется ... однако разве это не относится и к решению для базы данных? С другой стороны, решение для базы данных дает вам некоторые преимущества: вы можете использовать его, даже если документы содержат так много слов, что индексные файлы больше не помещаются в памяти (маловероятно, поскольку даже список всех английских слов будет поместится в память любого обычного пользовательского ПК); однако, если вам нужно загрузить индексные файлы огромного количества документов, тогда память может стать проблемой. Хорошо, вы можете обойти это, используя хитрые приемы (например, поиск непосредственно в файлах, которые вы сопоставили с памятью с помощью mmap и т. д.), Но это те же приемы, которые базы данных уже используют для выполнения быстрого поиска, поэтому зачем изобретать заново колесо? Кроме того, вы также можете предотвратить проблемы с блокировкой между поиском слов и обновлением индексов при изменении документа (то есть, если база данных может выполнять блокировку за вас или может выполнять обновление или обновления как атомарную операцию). Для веб-решения с вызовами AJAX для обновления списка использование базы данных, вероятно, является лучшим решением (мое первое решение вполне подходит, если это локально работающее приложение, написанное на языке низкого уровня, например C).

Если вам хочется сделать все это за один вызов select (что может быть неоптимальным, но когда вы динамически обновляете веб-контент с помощью AJAX, это обычно оказывается решением, вызывающим наименьшую головную боль), вам необходимо СОЕДИНЯТЬ все три таблицы вместе. Возможно, SQL немного ржавый, но я попробую:

SELECT COUNT(Document.idDoc) AS NumOfHits, Documents.Name AS Name, Documents.Location AS Location 
FROM Documents INNER JOIN Word_Docs ON Word_Docs.idDoc=Documents.idDoc 
INNER JOIN Words ON Words.idWord=Words_Docs.idWord
WHERE Words.Word IN ('Word1', 'Word2', 'Word3', ..., 'WordX')
GROUP BY Document.idDoc HAVING NumOfHits=X

Ладно, возможно, это не самый быстрый выбор ... Думаю, это можно сделать быстрее. В любом случае, он найдет все совпадающие документы, содержащие хотя бы одно слово, затем сгруппирует все равные документы вместе по идентификатору, посчитает, сколько их было сгруппировано в togetehr, и, наконец, покажет только результаты, где NumOfHits (количество слов, найденных в инструкции IN) равно количеству слов в операторе IN (если вы ищете 10 слов, X равно 10).

Контент документа статичен (не изменится); файлов больше 1 гигабайта, и он, вероятно, будет расти. Придется изучить остальной ваш ответ.

slashmais 29.09.2008 13:57

Google Desktop Search или аналогичный инструмент может удовлетворить ваши требования.

Ответ принят как подходящий

То, о чем вы говорите, известно как инвертированный индекс, или список сообщений, и действует аналогично тому, что вы предлагаете, и тому, что предлагает Меки. Об инвертированных индексах написано много; статья в Википедии - хорошее место для начала.

Лучше, чем пытаться построить его самостоятельно, использовать существующую реализацию инвертированного индекса. И MySQL, и последние версии PostgreSQL по умолчанию имеют полнотекстовую индексацию. Вы также можете проверить Lucene для независимого решения. При написании инвертированного индекса хорошо необходимо учитывать множество вещей, включая токенизацию, стемминг, многословные запросы и т. д. И т. Д., И готовое решение сделает все это за вас.

Другие вопросы по теме