文档章节

利用Lucene实现文本自动分类

p
 pangyuke
发布于 2016/11/07 22:20
字数 987
阅读 49
收藏 3

lucene是著名的开源技术,主要是作为全文检索使用。但是lucene存在很多隐藏的属性,文本分类就是其中的一种。

先上代码

//创建索引
public void createIndex() throws Exception {

    String[] nuts = {"dried longan raisin currant ginkgo prunes cranberry fig red date",
                     "apricot flesh Beijing flowering crab greengage hawthorn olive",
				     "apricot kernel dessicated coconut dried persimmon dried peach",
				     "dried apricot glace cherry/candied cherry Loquats in syrup hazelnut pine seed",
				     "chestnut Chinese chestnut macadamia/queensland nut cashew nut pepitas pine nut almond walnut",
				     "peanut pistachio areca nut beechnut", "apricot flesh Beijing flowering crab greengage hawthorn olive",
				     "apricot kernel dessicated coconut dried persimmon dried peach",
				     "apricot flesh Beijing flowering crab greengage hawthorn olive",
				     "apricot kernel dessicated coconut dried persimmon dried peach",
				     "dried apricot glace cherry/candied cherry Loquats in syrup hazelnut pine seed",
				     "chestnut Chinese chestnut macadamia/queensland nut cashew nut pepitas pine nut almond walnut",
				     "peanut pistachio areca nut beechnut",
				     "apricot flesh Beijing flowering crab greengage hawthorn olive" };

    String[] fruits = { "apple pear apricot peach grape banana  pineapple plum",
				        "watermelon orange lemon mango strawberry medlar mulberry nectarine cherry",
				        "pomegranate fig tangerine persimmon walnut hazelnutpeanut date chestnut currant coconut",
				        "bilberry blackberry avocado black currantblood orange citron damson almond",
				        "nutmeg papaya guava  pistachio prickly pear  raspberry ",
				        "watermelon orange lemon mango strawberry medlar mulberry nectarine cherry",
				        "bilberry blackberry avocado black currantblood orange citron damson almond",
        				"nutmeg papaya guava  pistachio prickly pear  raspberry " };

    File file = new File("D:/classindex");
    //如果已存在就删除
    if (file.exists()) {
        if (file.isFile()) {
                file.delete();
        } else if (file.isDirectory()) {
                File[] files = file.listFiles();
				for (int i = 0; i < files.length; i++) {
					files[i].delete();
				}
				file.delete();
        }
    }

    Directory dir = FSDirectory.open(file);
    IndexWriter w = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), true, 	IndexWriter.MaxFieldLength.UNLIMITED);

    for (String string : nuts) {

        Document doc = new Document();
        doc.add(new Field("category", "nuts", Field.Store.YES, Field.Index.NOT_ANALYZED));
        doc.add(new Field("content", string, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
        w.addDocument(doc);
    }

    for (String string : fruits) {

        Document doc = new Document();
        doc.add(new Field("category", "fruits", Field.Store.YES, Field.Index.NOT_ANALYZED));
        doc.add(new Field("content", string, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
        w.addDocument(doc);
    }

    w.close();
    dir.close();
}

//建立分类向量
public Map buildCategoryVectors() throws IOException {

    Map categoryMap = new TreeMap();

    IndexReader reader = IndexReader.open(FSDirectory.open(new File("D:/classindex")));

    int maxDoc = reader.maxDoc();

    for (int i = 0; i < maxDoc; i++) {
        if (!reader.isDeleted(i)) {
            Document doc = reader.document(i);
            String category = doc.get("category");

            Map vectorMap = (Map) categoryMap.get(category);
            if (vectorMap == null) {
                vectorMap = new TreeMap();
                categoryMap.put(category, vectorMap);
            }

            TermFreqVector termFreqVector = reader.getTermFreqVector(i, "content");

            String[] terms = termFreqVector.getTerms();
            int[] freqs = termFreqVector.getTermFrequencies();

            for (int j = 0; j < terms.length; j++) {
                String term = terms[j];

                if (vectorMap.containsKey(term)) {
                    Integer value = (Integer) vectorMap.get(term);
                    vectorMap.put(term, new Integer(value.intValue() + freqs[j]));
                } else {
                    vectorMap.put(term, new Integer(freqs[j]));
				}
			}
		}
	}
	return categoryMap;
}

//获取分类结果方法
public String getCategory(Map categoryMap, String content) {
    String[] words = content.split(" ");

    Iterator categoryIterator = categoryMap.keySet().iterator();
    double bestAngle = Double.MAX_VALUE;
    String bestCategory = null;

    while (categoryIterator.hasNext()) {
        String category = (String) categoryIterator.next();
        double angle = computeAngle(categoryMap, words, category);
        if (angle < bestAngle) {
            bestAngle = angle;
            bestCategory = category;
        }
    }
    return bestCategory;
}

//计算向量夹角,弧度
private double computeAngle(Map categoryMap, String[] words, String category){
    Map vectorMap = (Map) categoryMap.get(category);
    int dotProduct = 0;
    int sumOfSquares = 0;
    for (String word : words) {
        int categoryWordFreq = 0;
        if (vectorMap.containsKey(word)) {
            categoryWordFreq = ((Integer)vectorMap.get(word)).intValue();
        }
        dotProduct += categoryWordFreq;
        sumOfSquares += categoryWordFreq * categoryWordFreq;
    }

    double denominator;
    if (sumOfSquares == words.length) {
        denominator = sumOfSquares;
	} else {
        denominator = Math.sqrt(sumOfSquares) * Math.sqrt(words.length);
    }

    double ratio = dotProduct / denominator;

    return Math.acos(ratio);
}

//测试主程序
public static void main(String[] args) {
    try {
        PublishTest p = new PublishTest();
        p.createIndex();
        Map categoryMap = p.buildCategoryVectors();
        System.out.println(p.getCategory(categoryMap, "papaya chestnut mulberry blood orange fig Chinese chestnut Loquats"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

以上代码实现了水果(fruits)和干果(nuts)的自动分类。 按照分类算法的一般步骤,可以分为样本训练和分类预测2大步骤。

我们逐个的看方法:

createIndex实现了索引的创建,索引包含2个字段category(分类)和content(具体文本内容),nuts数组和fruits数组分别为训练的样本,为简单期间我们使用英文单词,做标准的分词处理。

buildCategoryVectors实现了分类向量的建立,以分类,单词词频建立一个二级的map对象。

以上2个方法可以看成是样本训练。

computeAngle实现了向量夹角的计算,那么什么是向量夹角?简单的说就是2个空间向量的夹角,用数学表达为cosθ=(A·B)/(|A|·|B|),其中A表示个单词词频组成的向量,B表示待分类文本分析得出的向量(是一个多数为0,少数为1的向量,用A中的各个单词做比较,1表示存在,0表示不存在)。A与B的点积除以A的模与B的模的乘积,在此例中的意义是θ越小,2个分类就接近。

getCategory最终通过computeAngle得到一个夹角最小的,就是所得到的分类。

在最终的测试程序,计算出的数值为:

fruits:0.7056503290095426

nuts:0.5222329678670935

于是预测文本的分类是fruits。

© 著作权归作者所有

共有 人打赏支持
p
粉丝 0
博文 2
码字总数 1655
作品 0
苏州
部门经理
私信 提问
实战 Lucene,第 1 部分: 初识 Lucene

本文首先介绍了 Lucene 的一些基本概念,然后开发了一个应用程序演示了利用 Lucene 建立索引并在该索引上进行搜索的过程。 朋 周登 (zhoudengpeng@yahoo.com.cn), 软件工程师 2006 年 4 月 ...

凡16
2013/09/27
0
0
[转] 实战 Lucene,第 1 部分: 初识 Lucene

Lucene 简介 Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta 家族中的一个开源项目。也...

小败
2012/02/26
0
0
企业级搜索应用服务器solr介绍

简介 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出...

_夏天的风_
2014/09/03
0
0
9个基于Java的搜索引擎框架

9个基于Java的搜索引擎框架 [导读] Lucene是目前最受欢迎的Java全文搜索框架,准确地说,它是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene为开发人员...

引鸩怼孑
2015/07/30
0
0
一步一步学solr:什么是solr?

简介 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出...

王爵nice
2014/07/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

matlab-线性代数 简单方程组求根(有唯一解) 非齐次线性方程组:常数项不全为零

  matlab : R2018a 64bit     OS : Windows 10 x64 typesetting : Markdown    blog : my.oschina.net/zhichengjiu    gitee : gitee.com/zhichengjiu   code clearclc% 2x+......

志成就
29分钟前
1
0
Ubuntu 时间同步配置备忘

缘起 目前使用的 Ubuntu 18 下经常出现时间错误,查了下是默认读取 NTP 服务器的时候出现了 timeout,几次手工修改后一重启就故态复萌了,至于这个问题应该是怪机房还是 GFW,就不清楚了。 ...

郁也风
50分钟前
0
0
计算最佳线程数

计算出应该用于应用程序的理论最佳线程数有助于我们的程序的性能,应用程序运行时特征主要有CPU密集型工作和主要等待IO两种特征,或者是混合一起。 CPU 任务 threads = number of CPUs + 1 在...

woshixin
今天
3
0
搜索引擎(Solr-索引详解2)

学习目标 1.掌握SolrJ的使用。 2.掌握索引API 3.掌握结构化数据导入DIH SolrJ介绍 SolrJ是什么? Solr提供的用于JAVA应用中访问solr服务API的客户端jar。在我们的应用中引入solrj: <depende...

这很耳东先生
今天
3
0
待整理完--分享如何一个月在阿里云账户多了700元

服务器领券地址

吴伟祥
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部