C#使用iKvm黑科技無縫接入JVM生態

程式設計實驗室發表於2023-10-06

前言

時間過得飛快,一轉眼國慶假期也要過去了,再不更新部落格就太鹹魚了……

最近在開發AIHub的時候想找個C#能用的命名實體識別庫,但一直沒找到,AI生態方面C#確實不太豐富,這塊還是得Python,但我又不想跟LLM一樣用gRPC的方式來呼叫,感覺有點麻煩。

這時候發現好像JVM生態有不少這類NLP工具,比如 Standford NLP 、HanLP這類。所以就想到之前在網上看到的iKvm,我直接把JVM生態白嫖來使用?

關於iKvm

看官方的介紹

IKVM is an implementation of Java for the Microsoft .NET platform. It can be used to quickly and easily:

  • Execute compiled Java code (bytecode) on .NET Framework or .NET Core
  • Convert bytecode to a .NET assembly to directly access its API in a .NET project

These tasks can be done without porting source code to .NET.

有兩種工作方式:

  • 直接在C#裡呼叫 jar 包執行
  • 將 jar 包轉譯為 .Net 平臺的 dll ,然後引用執行

一般選第二種就行,第一種就是動態呼叫,根本沒程式碼提示,不想考慮這種方式。

iKvm 其實是一套體系來的,裡面包含了完整的 JDK 標準庫和執行時啥的,我粗略看了下,什麼 swing、xml、media啥的一應俱全,還能支援 jdk 的反射。

並且還附帶有現代的構建工具 maven!

PS: gradle 不知道有沒有,我還沒試過。

關於依賴處理

雖說 iKvm 支援 maven 非常的方便,但是它並不能處理一個包中的依賴關係!

例如引用了 StarAI 這個包,它又依賴於 Transformer 這個庫,在maven中會自動下載所有依賴進行 build

但是 iKvm 的 maven 沒辦法自動處理依賴,所以只能手動把 StarAI 和 transformer 這倆庫都新增到配置裡。

開始使用

本文以 HanLP 為例

依賴準備

首先新增倆 nuget 依賴

dotnet add package IKVM
dotnet add package IKVM.Maven.Sdk

或者直接編輯專案檔案

<ItemGroup>
    <PackageReference Include="IKVM" Version="8.6.4" />
    <PackageReference Include="IKVM.Maven.Sdk" Version="1.5.5" />
</ItemGroup>

然後再專案檔案裡面新增 maven 依賴,直接從 mvn repository 上覆制下來就完事了,非常的方便!

給不熟悉 Java 的同學指個路: https://mvnrepository.com/

<ItemGroup>
    <MavenReference Include="hanlp">
        <groupId>com.hankcs</groupId>
        <artifactId>hanlp</artifactId>
        <version>portable-1.8.4</version>
    </MavenReference>
</ItemGroup>

儲存,之後IDE會自動執行操作,會自動下載 iKvm 需要的依賴,各平臺的 JDK 和 runtime 之類的,並且會自動從 maven 上把 jar 包下載下來並轉譯成 .Net 平臺的 dll

這個過程需要一段時間,請耐心等待。

如果沒有自動執行請手動執行

dotnet restore
dotnet build

開始編碼

這裡以 HanLP 的句子成分分析功能為例

using com.hankcs.hanlp.model.crf;
using com.hankcs.hanlp.model.perceptron;
using com.hankcs.hanlp.seg;
using com.hankcs.hanlp.seg.common;

namespace AIHub.Algo.HanLP;

public class NER {
    private readonly string _modelPath;

    public NER(string modelPath) {
        _modelPath = modelPath;
    }

    public void Recognize(string input) {
        PerceptronLexicalAnalyzer analyzer = new PerceptronLexicalAnalyzer(
            Path.Combine(_modelPath, "cws.bin"),
            Path.Combine(_modelPath, "pos.bin"),
            Path.Combine(_modelPath, "ner.bin")
        );

        var result = analyzer.analyze(input);
        Console.WriteLine(result);
    }
}

測試時直接呼叫 Recognize 方法即可。

參考資料

相關文章