从 Java 查询 Windows 搜索

发布于 2024-07-17 23:49:28 字数 375 浏览 13 评论 0原文

我想从 Java 直接(或间接)查询 Windows Vista 搜索服务。

我知道可以使用 search-ms: 协议进行查询,但我想在应用程序中使用结果。

我在 Windows Search API 中找到了很好的信息,但没有与爪哇。

我将标记为已接受的答案,它提供了有关如何实现这一目标的有用且明确的信息。

提前致谢。

编辑

在我将其标记为已接受之前,有人有 JACOB 样本吗? :)

I would like to get to query Windows Vista Search service directly ( or indirectly ) from Java.

I know it is possible to query using the search-ms: protocol, but I would like to consume the result within the app.

I have found good information in the Windows Search API but none related to Java.

I would mark as accepted the answer that provides useful and definitive information on how to achieve this.

Thanks in advance.

EDIT

Does anyone have a JACOB sample, before I can mark this as accepted?
:)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

稚然 2024-07-24 23:49:28

您可能想了解其中一种 Java-COM 集成技术。 我个人曾与 JACOB (JAva COm Bridge) 合作过:

这是相当麻烦(认为只使用反射工作),但为我完成了工作(快速概念证明,从 Java 内部访问 MapPoint)。

我所知道的唯一其他此类技术是 Jawin,但我没有任何个人经验:

更新 04/26/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 位于您的类路径中,并且 jamin.dll 位于您的路径(或 java.library.path 系统属性)中。 此代码只是打开到本地 Windows 桌面搜索索引的 ADO 连接,查询带有关键字“Foo”的文档,并打印出结果文档的一些关键属性。

如果您有任何疑问或需要我澄清任何事情,请告诉我。

2009 年 4 月 27 日更新:
我也尝试在 JACOB 中实现同样的事情,并将做一些基准测试来比较两者之间的性能差异。 我可能在 JACOB 中做错了什么,但它似乎始终使用 10 倍以上的内存。 如果我有时间的话,我也会致力于 jcom 和 com4j 实现,并尝试找出一些我认为是由于某处缺乏线程安全性造成的怪癖。 我什至可以尝试基于 JNI 的解决方案。 我预计所有事情都会在 6-8 周内完成。

2009 年 4 月 28 日更新:
这只是针对那些一直关注和好奇的人的更新。 事实证明,不存在线程问题,我只需要显式关闭数据库资源,因为 OLE DB 连接可能是在操作系统级别汇集的(无论如何我可能应该关闭连接......)。 我认为我不会对此进行任何进一步的更新。 如果有人遇到任何问题,请告诉我。

更新 05/01/2009:
根据 Oscar 的要求添加了 JACOB 示例。 从 COM 角度来看,这经历了完全相同的调用序列,只是使用了 JACOB。 虽然最近 JACOB 的工作确实更加积极,但我也注意到它非常消耗内存(使用的内存是 Jawin 版本的 10 倍)

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();
        }
    }
}

You may want to look at one of the Java-COM integration technologies. I have personally worked with JACOB (JAva COm Bridge):

Which was rather cumbersome (think working exclusively with reflection), but got the job done for me (quick proof of concept, accessing MapPoint from within Java).

The only other such technology I'm aware of is Jawin, but I don't have any personal experience with it:

Update 04/26/2009:
Just for the heck of it, I did more research into Microsoft Windows Search, and found an easy way to integrate with it using OLE DB. Here's some code I wrote as a proof of concept:

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();
        }
    }
}

To compile this, you'll need to make sure that the JAWIN JAR is in your classpath, and that jawin.dll is in your path (or java.library.path system property). This code simply opens an ADO connection to the local Windows Desktop Search index, queries for documents with the keyword "Foo," and print out a few key properties on the resultant documents.

Let me know if you have any questions, or need me to clarify anything.

Update 04/27/2009:
I tried implementing the same thing in JACOB as well, and will be doing some benchmarks to compare performance differences between the two. I may be doing something wrong in JACOB, but it seems to consistently be using 10x more memory. I'll be working on a jcom and com4j implementation as well, if I have some time, and try to figure out some quirks that I believe are due to the lack of thread safety somewhere. I may even try a JNI based solution. I expect to be done with everything in 6-8 weeks.

Update 04/28/2009:
This is just an update for those who've been following and curious. Turns out there are no threading issues, I just needed to explicitly close my database resources, since the OLE DB connections are presumably pooled at the OS level (I probably should have closed the connections anyway...). I don't think I'll be any further updates to this. Let me know if anyone runs into any problems with this.

Update 05/01/2009:
Added JACOB example per Oscar's request. This goes through the exact same sequence of calls from a COM perspective, just using JACOB. While it's true JACOB has been much more actively worked on in recent times, I also notice that it's quite a memory hog (uses 10x as much memory as the Jawin version)

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();
        }
    }
}
掩于岁月 2024-07-24 23:49:28

正如这里的几篇文章建议您可以使用商业或免费框架(如 JACOB、JNBridge、J-Integra 等)在 Java 和 .NET 或 COM 之间建立桥梁。
事实上,我有过与这些第三方之一的合作经历(一个昂贵的:-)),我必须说我会尽力避免将来重复这个错误。 原因是它涉及到许多你无法真正调试的“巫毒”东西,当出现问题时要理解问题所在是非常复杂的。

我建议您实现的解决方案是创建一个简单的 .NET 应用程序来实际调用 Windows 搜索 API。 完成此操作后,您需要在该组件和 Java 代码之间建立通信通道。 这可以通过多种方式完成,例如通过向应用程序定期提取的小型数据库发送消息。 或者在机器 IIS 上注册此组件(如果存在)并公开简单的 WS API 来与其通信。

我知道这可能听起来很麻烦,但明显的优点是:a)您使用 Windows 搜索 API 理解的语言(.NET 或 COM)与它进行通信,b)您可以控制所有应用程序路径。

As few posts here suggest you can bridge between Java and .NET or COM using commercial or free frameworks like JACOB, JNBridge, J-Integra etc..
Actually I had an experience with with one of these third parties (an expensive one :-) ) and I must say I will do my best to avoid repeating this mistake in the future. The reason is that it involves many "voodoo" stuff you can't really debug, it's very complicated to understand what is the problem when things go wrong.

The solution I would suggest you to implement is to create a simple .NET application that makes the actual calls to the windows search API. After doing so, you need to establish a communication channel between this component and your Java code. This can be done in various ways, for example by messaging to a small DB that your application will periodically pull. Or registering this component on the machine IIS (if exists) and expose simple WS API to communicate with it.

I know that it may sound cumbersome but the clear advantages are: a) you communicate with windows search API using the language it understands (.NET or COM) , b) you control all the application paths.

糖果控 2024-07-24 23:49:28

您无法仅使用 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();
    }
}

Any reason why you couldn't just use Runtime.exec() to query via search-ms and read the BufferedReader with the result of the command? For example:

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();
    }
}
一抹淡然 2024-07-24 23:49:28

有几个库用于从 java 调用 COM 对象,有些是开源的(但它们的学习曲线较高),有些是闭源的并且具有更快的学习曲线。 一个闭源示例是 EZCom。 商业的也倾向于从 Windows 调用 java,这是我在开源中从未见过的。

对于您的情况,我建议您在自己的 .NET 类中进行调用(我想使用 C#,因为它最接近 Java,而不涉及有争议的 J#),并专注于与 .NET dll 的互操作性。 这样Windows编程变得更容易,Windows和java之间的接口也更简单。

如果您正在寻找如何使用 java com 库,那么 MSDN 是错误的地方。 但是 MSDN 将帮助您从 .NET 中编写所需的内容,然后查看有关从 .NET 对象调用您需要的一两个方法的 com 库教程。

编辑:

鉴于有关使用 Web 服务的答案中的讨论,您可以(并且可能会有更好的运气)构建一个调用嵌入式 java Web 服务器的小型 .NET 应用程序,而不是尝试使 .NET 具有嵌入式 Web 服务,并使 java 成为调用的使用者。 对于嵌入式 Web 服务器,我的研究表明 Winstone 很好。 不是最小的,但更灵活。

使其工作的方法是从 java 启动 .NET 应用程序,并让 .NET 应用程序在计时器或循环上调用 Web 服务以查看是否有请求,如果有,则处理它并发送响应。

There are several libraries out there for calling COM objects from java, some are opensource (but their learning curve is higher) some are closed source and have a quicker learning curve. A closed source example is EZCom. The commercial ones tend to focus on calling java from windows as well, something I've never seen in opensource.

In your case, what I would suggest you do is front the call in your own .NET class (I guess use C# as that is closest to Java without getting into the controversial J#), and focus on making the interoperability with the .NET dll. That way the windows programming gets easier, and the interface between Windows and java is simpler.

If you are looking for how to use a java com library, the MSDN is the wrong place. But the MSDN will help you write what you need from within .NET, and then look at the com library tutorials about invoking the one or two methods you need from your .NET objects.

EDIT:

Given the discussion in the answers about using a Web Service, you could (and probably will have better luck) build a small .NET app that calls an embedded java web server rather than try to make .NET have the embedded web service, and have java be the consumer of the call. For an embedded web server, my research showed Winstone to be good. Not the smallest, but is much more flexible.

The way to get that to work is to launch the .NET app from java, and have the .NET app call the web service on a timer or a loop to see if there is a request, and if there is, process it and send the response.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文