【Neo4j】踩坑大会-Neo4J用中文索引
正在用的Neo4j是当前最新版:3.1.0,各种踩坑。说一下如何在Neo4j 3.1.0中使用中文索引。选用了IKAnalyzer做分词器。
1. 首先参考文章:
https://segmentfault.com/a/1190000005665612
里面大致讲了用IKAnalyzer做索引的方式。但并不清晰,实际上,这篇文章的背景是用嵌入式Neo4j,即Neo4j一定要嵌入在你的Java应用中(https://neo4j.com/docs/java-reference/current/#tutorials-java-embedded),切记。否则无法使用自定义的Analyzer。其次,文中的方法现在用起来已经有问题了,因为Neo4j 3.1.0用了lucene5.5,故官方的IKAnalyzer已经不适用了。
2. 修正
转用 IKAnalyzer2012FF_u1.jar,在Google可以下载到(https://code.google.com/archive/p/ik-analyzer/downloads)。这个版本的IKAnalyzer是有小伙伴修复了IKAnalyzer不适配lucene3.5以上而修改的一个版本。但是用了这个包仍有问题,报错提示:
Caused by: java.lang.AbstractMethodError: org.apache.lucene.analysis.Analyzer.createComponents(Ljava/lang/String;)Lorg/apache/lucene/analysis/Analyzer$TokenStreamComponents;
即IKAnalyzer的Analyzer类和当前版本的lucene仍有不适配的地方。
解决方案:再增加两个类
-
package com.uc.wa.function;
-
-
import org.apache.lucene.analysis.Analyzer;
-
import org.apache.lucene.analysis.Tokenizer;
-
-
public class IKAnalyzer5x extends Analyzer{
-
-
private boolean useSmart;
-
-
public boolean useSmart() {
-
return useSmart;
-
}
-
-
public void setUseSmart(boolean useSmart) {
-
this.useSmart = useSmart;
-
}
-
-
public IKAnalyzer5x(){
-
this(false);
-
}
-
-
public IKAnalyzer5x(boolean useSmart){
-
super();
-
this.useSmart = useSmart;
-
}
-
-
-
/**
-
protected TokenStreamComponents createComponents(String fieldName, final Reader in) {
-
Tokenizer _IKTokenizer = new IKTokenizer(in , this.useSmart());
-
return new TokenStreamComponents(_IKTokenizer);
-
}
-
**/
-
-
-
/**
-
* 重写最新版本的createComponents
-
* 重载Analyzer接口,构造分词组件
-
*/
-
@Override
-
protected TokenStreamComponents createComponents(String fieldName) {
-
Tokenizer _IKTokenizer = new IKTokenizer5x(this.useSmart());
-
return new TokenStreamComponents(_IKTokenizer);
-
}
-
}
-
package com.uc.wa.function;
-
-
import java.io.IOException;
-
-
import org.apache.lucene.analysis.Tokenizer;
-
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
-
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
-
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
-
import org.wltea.analyzer.core.IKSegmenter;
-
import org.wltea.analyzer.core.Lexeme;
-
-
public class IKTokenizer5x extends Tokenizer{
-
-
//IK�ִ���ʵ��
-
private IKSegmenter _IKImplement;
-
-
//��Ԫ�ı�����
-
private final CharTermAttribute termAtt;
-
//��Ԫλ������
-
private final OffsetAttribute offsetAtt;
-
//��Ԫ�������ԣ������Է���ο�org.wltea.analyzer.core.Lexeme�еķ��ೣ����
-
private final TypeAttribute typeAtt;
-
//��¼���һ����Ԫ�Ľ���λ��
-
private int endPosition;
-
-
-
/**
-
public IKTokenizer(Reader in , boolean useSmart){
-
super(in);
-
offsetAtt = addAttribute(OffsetAttribute.class);
-
termAtt = addAttribute(CharTermAttribute.class);
-
typeAtt = addAttribute(TypeAttribute.class);
-
_IKImplement = new IKSegmenter(input , useSmart);
-
}**/
-
-
/**
-
* Lucene 5.x Tokenizer��������캯��
-
* ʵ�����µ�Tokenizer�ӿ�
-
* @param useSmart
-
*/
-
public IKTokenizer5x(boolean useSmart){
-
super();
-
offsetAtt = addAttribute(OffsetAttribute.class);
-
termAtt = addAttribute(CharTermAttribute.class);
-
typeAtt = addAttribute(TypeAttribute.class);
-
_IKImplement = new IKSegmenter(input , useSmart);
-
}
-
-
/* (non-Javadoc)
-
* @see org.apache.lucene.analysis.TokenStream#incrementToken()
-
*/
-
@Override
-
public boolean incrementToken() throws IOException {
-
//������еĴ�Ԫ����
-
clearAttributes();
-
Lexeme nextLexeme = _IKImplement.next();
-
if(nextLexeme != null){
-
//��Lexemeת��Attributes
-
//���ô�Ԫ�ı�
-
termAtt.append(nextLexeme.getLexemeText());
-
//���ô�Ԫ����
-
termAtt.setLength(nextLexeme.getLength());
-
//���ô�Ԫλ��
-
offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());
-
//��¼�ִʵ����λ��
-
endPosition = nextLexeme.getEndPosition();
-
//��¼��Ԫ����
-
typeAtt.setType(nextLexeme.getLexemeTypeString());
-
//����true��֪�����¸���Ԫ
-
return true;
-
}
-
//����false��֪��Ԫ������
-
return false;
-
}
-
-
/*
-
* (non-Javadoc)
-
* @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)
-
*/
-
@Override
-
public void reset() throws IOException {
-
super.reset();
-
_IKImplement.reset(input);
-
}
-
-
@Override
-
public final void end() {
-
// set final offset
-
int finalOffset = correctOffset(this.endPosition);
-
offsetAtt.setOffset(finalOffset, finalOffset);
-
}
-
}
解决 IKAnalyzer2012FF_u1.jar和lucene5不适配的问题。使用时用IKAnalyzer5x替换IKAnalyzer即可。
3. 最后
Neo4j中文索引建立和搜索示例:
-
/**
-
* 为单个结点创建索引
-
*
-
* @param propKeys
-
*/
-
public static void createFullTextIndex(long id, List<String> propKeys) {
-
log.info("method[createFullTextIndex] begin.propKeys<"+propKeys+">");
-
Index<Node> entityIndex = null;
-
-
try (Transaction tx = Neo4j.graphDb.beginTx()) {
-
entityIndex = Neo4j.graphDb.index().forNodes("NodeFullTextIndex",
-
MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "analyzer", IKAnalyzer5x.class.getName()));
-
-
Node node = Neo4j.graphDb.getNodeById(id);
-
log.info("method[createFullTextIndex] get node id<"+node.getId()+"> name<"
-
+node.getProperty("knowledge_name")+">");
-
/**获取node详细信息*/
-
Set<Map.Entry<String, Object>> properties = node.getProperties(propKeys.toArray(new String[0]))
-
.entrySet();
-
for (Map.Entry<String, Object> property : properties) {
-
log.info("method[createFullTextIndex] index prop<"+property.getKey()+":"+property.getValue()+">");
-
entityIndex.add(node, property.getKey(), property.getValue());
-
}
-
tx.success();
-
}
-
}
-
/**
-
* 使用索引查询
-
*
-
* @param query
-
* @return
-
* @throws IOException
-
*/
-
public static List<Map<String, Object>> selectByFullTextIndex(String[] fields, String query) throws IOException {
-
List<Map<String, Object>> ret = Lists.newArrayList();
-
try (Transaction tx = Neo4j.graphDb.beginTx()) {
-
IndexManager index = Neo4j.graphDb.index();
-
/**查询*/
-
Index<Node> addressNodeFullTextIndex = index.forNodes("NodeFullTextIndex",
-
MapUtil.stringMap(IndexManager.PROVIDER, "lucene", "analyzer", IKAnalyzer5x.class.getName()));
-
Query q = IKQueryParser.parseMultiField(fields, query);
-
-
IndexHits<Node> foundNodes = addressNodeFullTextIndex.query(q);
-
-
for(Node n : foundNodes){
-
Map<String, Object> m = n.getAllProperties();
-
if(!Float.isNaN(foundNodes.currentScore())){
-
m.put("score", foundNodes.currentScore());
-
}
-
log.info("method[selectByIndex] score<"+foundNodes.currentScore()+">");
-
ret.add(m);
-
}
-
tx.success();
-
} catch (IOException e) {
-
log.error("method[selectByIndex] fields<"+Joiner.on(",").join(fields)+"> query<"+query+">", e);
-
throw e;
-
}
-
return ret;
-
}
注意到,在这里我用了IKQueryParser,即根据我们的查询词和要查询的字段,自动构造Query。这里是绕过了一个坑:用lucene查询语句直接查的话,是有问题的。比如:“address:南昌市” 查询语句,会搜到所有带市字的地址,这是非常不合理的。改用IKQueryParser即修正这个问题。IKQueryParser是IKAnalyzer自带的一个工具,但在 IKAnalyzer2012FF_u1.jar却被删减掉了。因此我这里重新引入了原版IKAnalyzer的jar包,项目最终是两个jar包共存的。
到这里坑就踩得差不多了。
原文地址:https://blog.csdn.net/hereiskxm/article/details/54345261 </div>
【Neo4j】踩坑大会-Neo4J用中文索引的更多相关文章
- PLSQL Developer 中文乱码踩坑记
环境 操作系统版本: Windows 7 PL/SQL 版本: 12.0.1.1814 原因 由于 Oracle 服务器端和客户端字符集编码不一致引起的. 注意点 写在最前面,减少踩坑!!! 网上教程 ...
- Neo4j之坑
10个月前,我开始用neo4j做cmdb. 初体验下去neo4j很美好. 但是一年中发现一些问题, 仅仅是个人的体验.经供参考 查询语言 如果接触过Neo4j,都会为Cypher的简单和易用感觉到惊叹 ...
- 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密
你真的了解字典(Dictionary)吗? 从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...
- AI相关 TensorFlow -卷积神经网络 踩坑日记之一
上次写完粗浅的BP算法 介绍 本来应该继续把 卷积神经网络算法写一下的 但是最近一直在踩 TensorFlow的坑.所以就先跳过算法介绍直接来应用场景,原谅我吧. TensorFlow 介绍 TF是g ...
- 人工智能(AI)库TensorFlow 踩坑日记之一
上次写完粗浅的BP算法 介绍 本来应该继续把 卷积神经网络算法写一下的 但是最近一直在踩 TensorFlow的坑.所以就先跳过算法介绍直接来应用场景,原谅我吧. TensorFlow 介绍 TF是g ...
- 微信小程序踩坑集合
1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...
- C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式
C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...
- Nebula Exchange 工具 Hive 数据导入的踩坑之旅
摘要:本文由社区用户 xrfinbj 贡献,主要介绍 Exchange 工具从 Hive 数仓导入数据到 Nebula Graph 的流程及相关的注意事项. 1 背景 公司内部有使用图数据库的场景,内 ...
- Spark踩坑记——数据库(Hbase+Mysql)
[TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...
随机推荐
- DNS排查技术图谱
# DNS排查技术图谱 ## 应用程序视角- 应用程序 - 浏览器 - hostname cache - ping- 操作系统 - hostname cache - 域名解析器 - dig domai ...
- This inspection warns about local variables referenced before assignment.
关于 local variable 'has' referenced before assignment 问题 今天在django开发时,访问页面总是出现错误提示“local variable 'ha ...
- css3继承
不可继承的:display.margin.border.padding.background.height.min-height.max- height.width.min-width.max-wid ...
- delphi文件后缀全解
delphi文件后缀全解 1. 项目文件(.dpr):Delphi项目文件,用于保存窗体.单元等的信息,以及程序运行的初始化代码等,这种文件实际上包含了Pascal源代码. 2. 单元文件(.pas) ...
- Boring counting HDU - 3518 后缀自动机
题意: 对于给出的字符串S, 长度不超过1000, 求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次 题解: 将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出 ...
- python之常用的数据处理方法
1.生成6位数验证码 "".join([random.choice(chars) for i in range(6)]) 2.密码加密 import hashlib def enc ...
- Git部署项目
前言 学习Git的目标是要学会如何部署项目.Git是一种版本控制系统,与之对应的还有CVS和SVN,其中CVS和SVN都是集中式的版本控制,而Git是一种分布式的,在现代项目开发中,大多使用Git来管 ...
- node-express(1)建立post、get、跨域问题解决方案
首先下载express:npm i express let ess=require('express'); let app=ess(); let bodyParser=require('body-pa ...
- JAVA 调用c++ 扩展 批评那些垃圾,
//本人喜欢用命令行的方式,这样好理解原理 { 1 生成的要是X64 并且是release版本 不要预编译头的dll项目,就是创建的时是一个空dll项目 2 java 调用时要import com.m ...
- Delphi 时间函数:关于时间精确的几个函数和方法
//取毫秒级时间精度(方法一): var t1,t2:int64; r1:int64; begin t1:=GetTickCount;//获取开始计数 WINDOWS API sleep(1000); ...