Запрос Windows Search из Java - PullRequest
       29

Запрос Windows Search из Java

6 голосов
/ 23 апреля 2009

Я хотел бы получить запрос службы поиска Windows Vista напрямую (или косвенно) из Java.

Я знаю, что можно выполнять запрос с использованием протокола search-ms:, но я хотел бы использовать результат в приложении.

Я нашел хорошую информацию в API поиска Windows , но ни одна из них не связана с Java.

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

Заранее спасибо.

РЕДАКТИРОВАТЬ

Есть ли у кого-нибудь образец JACOB, прежде чем я смогу пометить его как принятый? :)

Ответы [ 4 ]

20 голосов
/ 25 апреля 2009

Возможно, вы захотите взглянуть на одну из технологий интеграции Java-COM. Я лично работал с JACOB (JAva COm Bridge):

Это было довольно громоздко (подумайте, работая исключительно с отражением), но сделало работу за меня (быстрое подтверждение концепции, доступ к MapPoint из Java).

Единственная другая технология, о которой я знаю, это Jawin, но у меня нет личного опыта:

Обновление от 26.04.2009: Просто, черт побери, я провел больше исследований в Microsoft Windows Search и нашел простой способ интеграции с ним с помощью OLE DB. Вот код, который я написал в качестве доказательства концепции:

public static void main(String[] args) {
    DispatchPtr connection = null;
    DispatchPtr results = null;
    try {
        Ole32.CoInitialize();
        connection = new DispatchPtr("ADODB.Connection");
        connection.invoke("Open",
            "Provider=Search.CollatorDSO;" +
            "Extended Properties='Application=Windows';");
        results = (DispatchPtr)connection.invoke("Execute",
            "select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
            "from SystemIndex " +
            "where contains('Foo')");
        int count = 0;
        while(!((Boolean)results.get("EOF")).booleanValue()) {
            ++ count;
            DispatchPtr fields = (DispatchPtr)results.get("Fields");
            int numFields = ((Integer)fields.get("Count")).intValue();

            for (int i = 0; i < numFields; ++ i) {
                DispatchPtr item =
                    (DispatchPtr)fields.get("Item", new Integer(i));
                System.out.println(
                    item.get("Name") + ": " + item.get("Value"));
            }
            System.out.println();
            results.invoke("MoveNext");
        }
        System.out.println("\nCount:" + count);
    } catch (COMException e) {
        e.printStackTrace();
    } finally {
        try {
            results.invoke("Close");
        } catch (COMException e) {
            e.printStackTrace();
        }
        try {
            connection.invoke("Close");
        } catch (COMException e) {
            e.printStackTrace();
        }
        try {
            Ole32.CoUninitialize();
        } catch (COMException e) {
            e.printStackTrace();
        }
    }
}

Для компиляции вам необходимо убедиться, что JAWIN JAR находится в вашем classpath, и что jawin.dll находится в вашем пути (или системном свойстве java.library.path). Этот код просто открывает подключение ADO к локальному индексу поиска Windows Desktop, запрашивает документы с ключевым словом «Foo» и распечатывает несколько ключевых свойств в итоговых документах.

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

Обновление от 27.04.2009: Я попытался реализовать то же самое в JACOB, и буду делать некоторые тесты для сравнения различий в производительности между ними. Возможно, я что-то не так делаю в JACOB, но похоже, что он постоянно использует в 10 раз больше памяти. Я также буду работать над реализацией jcom и com4j, если у меня будет время, и попытаюсь выяснить некоторые причуды, которые, как мне кажется, связаны с отсутствием безопасности потоков. Я могу даже попробовать решение на основе JNI. Я ожидаю, что все будет сделано через 6-8 недель.

Обновление от 28.04.2009: Это просто обновление для тех, кто следил и любопытно. Оказывается, нет проблем с многопоточностью, мне просто нужно было явно закрыть ресурсы базы данных, так как соединения OLE DB предположительно объединены в пул на уровне операционной системы (я, вероятно, в любом случае должен был закрыть соединения ...). Я не думаю, что буду дальнейшими обновлениями к этому. Дайте мне знать, если у кого-нибудь возникнут проблемы с этим.

Обновление 05.01.2009: Добавлен пример JACOB по запросу Оскара. Это проходит через ту же самую последовательность вызовов с точки зрения COM, просто используя JACOB. Хотя это правда, что в последнее время над JACOB работали гораздо активнее, я также заметил, что это довольно сложная память (использует в 10 раз больше памяти, чем версия Jawin)

public static void main(String[] args) {
    Dispatch connection = null;
    Dispatch results = null;

    try {
        connection = new Dispatch("ADODB.Connection");
        Dispatch.call(connection, "Open",
            "Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
        results = Dispatch.call(connection, "Execute",
            "select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
            "from SystemIndex " +
            "where contains('Foo')").toDispatch();
        int count = 0;
        while(!Dispatch.get(results, "EOF").getBoolean()) {
            ++ count;
            Dispatch fields = Dispatch.get(results, "Fields").toDispatch();
            int numFields = Dispatch.get(fields, "Count").getInt();

            for (int i = 0; i < numFields; ++ i) {
                Dispatch item =
                    Dispatch.call(fields, "Item", new Integer(i)).
                    toDispatch();
                System.out.println(
                    Dispatch.get(item, "Name") + ": " +
                    Dispatch.get(item, "Value"));
            }
            System.out.println();
            Dispatch.call(results, "MoveNext");
        }
    } finally {
        try {
            Dispatch.call(results, "Close");
        } catch (JacobException e) {
            e.printStackTrace();
        }
        try {
            Dispatch.call(connection, "Close");
        } catch (JacobException e) {
            e.printStackTrace();
        }
    }
}
3 голосов
/ 28 апреля 2009

Как отмечается в нескольких постах, вы можете соединять Java и .NET или COM с помощью коммерческих или бесплатных платформ, таких как JACOB, JNBridge, J-Integra и т. Д. На самом деле у меня был опыт общения с одной из этих третьих сторон (дорогой :-)), и я должен сказать, что сделаю все возможное, чтобы избежать повторения этой ошибки в будущем. Причина в том, что в нем много "вуду" вещей, которые вы не можете отладить, очень сложно понять, в чем проблема, когда что-то идет не так.

Решение, которое я бы предложил вам реализовать, заключается в создании простого .NET-приложения, которое выполняет реальные вызовы API поиска Windows. После этого вам нужно установить канал связи между этим компонентом и вашим Java-кодом. Это можно сделать различными способами, например, отправив сообщения на небольшую БД, которую ваше приложение будет периодически извлекать. Или зарегистрируйте этот компонент на компьютере IIS (если он существует) и предоставьте простой WS API для связи с ним.

Я знаю, что это может показаться громоздким, но очевидные преимущества заключаются в следующем: а) вы общаетесь с API поиска Windows, используя язык, который он понимает (.NET или COM), б) вы контролируете все пути приложений.

1 голос
/ 25 апреля 2009

Любая причина, почему вы не могли просто использовать Runtime.exec() для запроса через search-ms и прочитать BufferedReader с результатом команды? Например:

public class ExecTest {
    public static void main(String[] args) throws IOException {
        Process result = Runtime.getRuntime().exec("search-ms:query=microsoft&");

        BufferedReader output = new BufferedReader(new InputStreamReader(result.getInputStream()));
        StringBuffer outputSB = new StringBuffer(40000);
        String s = null;

        while ((s = output.readLine()) != null) {
            outputSB.append(s + "\n");
            System.out.println(s);
        }

        String result = output.toString();
    }
}
0 голосов
/ 26 апреля 2009

Существует несколько библиотек для вызова COM-объектов из Java, некоторые из них с открытым исходным кодом (но их кривая обучения выше), некоторые с закрытым исходным кодом и имеют более быструю кривую обучения. Пример закрытого источника: EZCom . Коммерческие, как правило, фокусируются также на вызове java из окон, чего я никогда не видел в open source.

В вашем случае я хотел бы предложить вам выполнить вызов в своем собственном классе .NET (я полагаю, использовать C #, так как он ближе всего к Java, не вдаваясь в противоречивый J #), и сосредоточиться на обеспечении взаимодействия с .NET dll. Таким образом, программирование Windows становится проще, а интерфейс между Windows и Java становится проще.

Если вы ищете, как использовать библиотеку java com, MSDN не то место. Но MSDN поможет вам написать то, что вам нужно, изнутри .NET, а затем взглянуть на руководства по библиотекам com по вызову одного или двух необходимых вам методов из ваших объектов .NET.

EDIT:

Учитывая обсуждение ответов об использовании веб-службы, вы можете (и, вероятно, вам повезет) создать небольшое приложение .NET, которое вызывает встроенный веб-сервер Java, а не пытаться заставить .NET иметь встроенный веб-сервис. И пусть Java будет потребителем звонка. Для встроенного веб-сервера мое исследование показало, что Winstone будет хорошим. Не самый маленький, но гораздо более гибкий.

Способ заставить это работать - запустить приложение .NET из Java и заставить приложение .NET вызывать веб-службу по таймеру или циклу, чтобы узнать, есть ли запрос и, если есть, обработать. это и отправьте ответ.

...