设为首页 收藏本站
查看: 1088|回复: 0

[经验分享] 使用solr实现pinyin分词,针对短词搜索,比如电影搜索

[复制链接]

尚未签到

发表于 2015-11-12 09:09:26 | 显示全部楼层 |阅读模式
1,增加solr拼音查询原理:

DSC0000.png

pinyin4j-2.5.0.jar

下载地址:
http://sourceforge.net/projects/pinyin4j/


solr环境使用3.6.2。
2,Token代码:

package com.freewebsys.index.analysis;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.ngram.NGramTokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
public class PinyinTokenizer extends Tokenizer {
private static final int DEFAULT_BUFFER_SIZE = 512;
private boolean done = false;
private int finalOffset;
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class);
private HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
// 链接字符串.
private String padding_char = " ";
// 构造函数.
public PinyinTokenizer(Reader reader) {
this(reader, DEFAULT_BUFFER_SIZE);
}
public PinyinTokenizer(Reader input, int bufferSize) {
super(input);
termAtt.resizeBuffer(bufferSize);
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
format.setVCharType(HanyuPinyinVCharType.WITH_V);
}
@Override
public final boolean incrementToken() throws IOException {
if (!done) {
clearAttributes();
done = true;
int upto = 0;
char[] buffer = termAtt.buffer();
System.out.println(String.valueOf(buffer));
while (true) {
final int length = input.read(buffer, upto, buffer.length
- upto);
if (length == -1)
break;
upto += length;
if (upto == buffer.length)
buffer = termAtt.resizeBuffer(1 + buffer.length);
}
termAtt.setLength(upto);
String str = termAtt.toString();
termAtt.setEmpty();
StringBuilder stringBuilder = new StringBuilder();
StringBuilder firstLetters = new StringBuilder();
StringBuilder cnLetters = new StringBuilder();
StringBuilder allPinYinLetters = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c < 128) {
stringBuilder.append(c);
} else {
try {
String[] strs = PinyinHelper.toHanyuPinyinStringArray(
c, format);
if (strs != null) {
// get first result by default
String first_value = strs[0];
// TODO more than one pinyin
// 拼接中文字符.
cnLetters.append(c);
cnLetters.append(this.padding_char);
// 全部拼音字符.
allPinYinLetters.append(first_value);
// 拼接拼音字符.
stringBuilder.append(first_value);
stringBuilder.append(this.padding_char);
// 拼接首字母字符.
firstLetters.append(first_value.charAt(0));
}
} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination.printStackTrace();
}
}
}
// let's join them
termAtt.append(stringBuilder.toString());
termAtt.append(this.padding_char);
termAtt.append(cnLetters.toString());
termAtt.append(this.padding_char);
termAtt.append(firstLetters.toString());
termAtt.append(this.padding_char);
// 将全部拼音分词成一个一个输入数据索引。
termAtt.append(mergeNGramPinYin(allPinYinLetters.toString()));
finalOffset = correctOffset(upto);
offsetAtt.setOffset(correctOffset(0), finalOffset);
return true;
}
return false;
}
@Override
public final void end() {
// set final offset
offsetAtt.setOffset(finalOffset, finalOffset);
}
@Override
public void reset(Reader input) throws IOException {
super.reset(input);
this.done = false;
}
public static String mergeNGramPinYin(String allPinYin) {
// 读取字符串
StringReader reader = new StringReader(allPinYin);
// 设置临时变量
String[] pinYinBuffer = null;
if (StringUtils.isNotBlank(allPinYin)) {
// 设置数组长度
pinYinBuffer = new String[allPinYin.length()];
StringBuffer tmpAppendPinYin = new StringBuffer();
NGramTokenizer nGramTokenizer = new NGramTokenizer(reader);
for (int i = 0; i < allPinYin.length(); i++) {
try {
// 循环递增
nGramTokenizer.incrementToken();
// 取得解析后的字符串
CharTermAttribute charTermAttribute = nGramTokenizer
.getAttribute(CharTermAttribute.class);
tmpAppendPinYin.append(String.valueOf(
charTermAttribute.buffer()).trim());
// 每次都给数据赋值.
pinYinBuffer = tmpAppendPinYin.toString();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 将结果按照空格合并.
return StringUtils.join(pinYinBuffer, &quot; &quot;);
}
}


PinyinTokenizerFactory:

package com.freewebsys.index.analysis;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.solr.analysis.BaseTokenizerFactory;
import java.io.Reader;
/**
*/
public class PinyinTokenizerFactory extends BaseTokenizerFactory {
@Override
public Tokenizer create(Reader input) {
return new PinyinTokenizer(input);
}
}




3,solr 的schema.xml配置:

对于 index和query分开配置:
<!-- standard_text.标准分词.创建使用pinyin分词,搜索不使用. -->
<fieldType name=&quot;standard_text&quot; class=&quot;solr.TextField&quot;
positionIncrementGap=&quot;100&quot;>
<analyzer type=&quot;index&quot;>
<tokenizer class=&quot;com.freewebsys.index.analysis.PinyinTokenizerFactory&quot; />
<filter class=&quot;solr.LowerCaseFilterFactory&quot; />
<filter class=&quot;solr.WordDelimiterFilterFactory&quot;
generateWordParts=&quot;1&quot; generateNumberParts=&quot;1&quot; catenateWords=&quot;0&quot;
catenateNumbers=&quot;1&quot; catenateAll=&quot;0&quot; splitOnCaseChange=&quot;1&quot; />
</analyzer>
<analyzer type=&quot;query&quot;>
<tokenizer class=&quot;solr.StandardTokenizerFactory&quot; />
</analyzer>
</fieldType>

4,使用分词效果:




DSC0001.png


  


  如果在管理后台测试可以看到上面的分词结果,就说明pinyin分词配置好了。

5,不足:
  目前看在搜索完成后,高亮显示还有点问题,因为索引里面增加了很多拼音。
  局限性,只能简单对比较段的内容进行分词,比如商品,电影,图书等,要是文字太长使用NGramTokenizer 分词就会增加一堆没用的pinyin。
  


  



版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-138157-1-1.html 上篇帖子: Solr Multicore意义 下篇帖子: Nutch + Solr + Hadoop 搭建分布式搜索引擎详细教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表