You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Hibernate Search 5.6.1中使用WordNet同义词?

解决Hibernate Search 5.6.1中使用WordNet同义词的问题

我之前在基于Hibernate Search 5.x开发搜索功能时,也碰到过用WordNet同义词替代静态文件的需求,刚好可以给你分享两种可行的方案:

方案一:预生成WordNet同义词静态文件

这种方式适合同义词不常更新的场景,先把WordNet里的同义词提取成Solr格式的静态文件,再交给SynonymFilterFactory使用。

步骤1:引入WordNet访问依赖

用JWNL(Java WordNet Library)来读取WordNet词库,在Maven中添加依赖:

<dependency>
    <groupId>net.sf.jwnl</groupId>
    <artifactId>jwnl</artifactId>
    <version>1.4.1</version>
</dependency>

步骤2:编写工具类提取同义词

写一个简单的Java程序,遍历WordNet的词库,提取同义词并输出成Solr兼容的格式(一行一个词项,同义词用逗号分隔):

import net.sf.jwnl.JWNL;
import net.sf.jwnl.data.IndexWord;
import net.sf.jwnl.data.POS;
import net.sf.jwnl.data.Synset;
import net.sf.jwnl.data.Word;
import net.sf.jwnl.dictionary.Dictionary;

import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class WordNetSynonymExporter {
    public static void main(String[] args) throws Exception {
        // 初始化JWNL(需要jwnl_properties.xml配置文件,指定WordNet路径)
        JWNL.initialize(WordNetSynonymExporter.class.getResourceAsStream("/jwnl_properties.xml"));
        Dictionary dictionary = Dictionary.getInstance();
        
        FileWriter writer = new FileWriter("src/main/resources/wordnet_synonyms.txt");
        
        // 遍历名词、动词、形容词等词性,按需调整
        for (POS pos : new POS[]{POS.NOUN, POS.VERB}) {
            IndexWord indexWord = dictionary.getIndexWordIterator(pos).next();
            while (indexWord != null) {
                Set<String> synonyms = new HashSet<>();
                // 添加当前词
                synonyms.add(indexWord.getLemma());
                // 获取同义词集
                for (Synset synset : indexWord.getSenses()) {
                    for (Word word : synset.getWords()) {
                        synonyms.add(word.getLemma());
                    }
                }
                // 写入文件,去重后用逗号分隔
                if (synonyms.size() > 1) {
                    writer.write(String.join(",", synonyms) + "\n");
                }
                indexWord = dictionary.getIndexWordIterator(pos).next();
            }
        }
        writer.close();
    }
}

步骤3:配置Hibernate Search注解

把生成的wordnet_synonyms.txt放到资源目录,然后修改你的TokenFilter配置:

@AnalyzerDef(name = "wordnetSynonymAnalyzer",
    tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
    filters = {
        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
        @TokenFilterDef(factory = SynonymFilterFactory.class,
            params = {
                @Parameter(name = "ignoreCase", value = "true"),
                @Parameter(name = "expand", value = "true"),
                @Parameter(name = "synonyms", value = "classpath:wordnet_synonyms.txt")
            })
    })

方案二:自定义同义词提供者动态读取WordNet

如果需要实时获取WordNet的同义词(比如词库会更新),可以自定义SynonymProvider,让SynonymFilterFactory直接从WordNet查询。

步骤1:实现自定义SynonymProvider

import net.sf.jwnl.JWNL;
import net.sf.jwnl.data.IndexWord;
import net.sf.jwnl.data.POS;
import net.sf.jwnl.data.Synset;
import net.sf.jwnl.data.Word;
import net.sf.jwnl.dictionary.Dictionary;
import org.apache.lucene.analysis.synonym.SynonymMap;
import org.apache.lucene.analysis.synonym.SynonymProvider;
import org.apache.lucene.util.CharsRef;

import java.io.IOException;
import java.util.*;

public class WordNetSynonymProvider implements SynonymProvider {
    private Dictionary dictionary;

    @Override
    public void init(Map<String, String> params) throws IOException {
        try {
            // 初始化JWNL
            JWNL.initialize(WordNetSynonymProvider.class.getResourceAsStream("/jwnl_properties.xml"));
            dictionary = Dictionary.getInstance();
        } catch (Exception e) {
            throw new IOException("Failed to initialize WordNet dictionary", e);
        }
    }

    @Override
    public SynonymMap build() throws IOException {
        SynonymMap.Builder builder = new SynonymMap.Builder(true);
        // 按需处理词性,这里以名词为例
        processPOS(builder, POS.NOUN);
        processPOS(builder, POS.VERB);
        return builder.build();
    }

    private void processPOS(SynonymMap.Builder builder, POS pos) throws IOException {
        try {
            IndexWord indexWord = dictionary.getIndexWordIterator(pos).next();
            while (indexWord != null) {
                String lemma = indexWord.getLemma();
                Set<String> synonyms = new HashSet<>();
                for (Synset synset : indexWord.getSenses()) {
                    for (Word word : synset.getWords()) {
                        synonyms.add(word.getLemma());
                    }
                }
                synonyms.remove(lemma);
                if (!synonyms.isEmpty()) {
                    // 添加当前词到同义词的映射
                    builder.add(new CharsRef(lemma), new CharsRef[]{new CharsRef(String.join(" ", synonyms))}, true);
                }
                indexWord = dictionary.getIndexWordIterator(pos).next();
            }
        } catch (Exception e) {
            throw new IOException("Failed to process WordNet POS: " + pos, e);
        }
    }
}

步骤2:配置注解使用自定义Provider

修改@TokenFilterDef,指定synonymsProvider参数替代synonyms文件:

@AnalyzerDef(name = "dynamicWordnetSynonymAnalyzer",
    tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
    filters = {
        @TokenFilterDef(factory = LowerCaseFilterFactory.class),
        @TokenFilterDef(factory = SynonymFilterFactory.class,
            params = {
                @Parameter(name = "ignoreCase", value = "true"),
                @Parameter(name = "expand", value = "true"),
                @Parameter(name = "synonymsProvider", value = "com.yourpackage.WordNetSynonymProvider")
            })
    })

注意事项

  • WordNet词库准备:需要下载WordNet的数据库文件(比如WordNet 3.1),并在jwnl_properties.xml中指定其路径。
  • 性能优化:自定义Provider时建议添加缓存,避免每次构建同义词映射都遍历WordNet,尤其是词库较大时。
  • 参数说明:expand=true会让同义词之间互相匹配(比如搜索"car"能匹配"automobile",搜索"automobile"也能匹配"car"),如果设置为false则是单向映射。

内容的提问来源于stack exchange,提问作者blackhippy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:30:12