elasticsearch

elasticsearch

pinyin分词 match和match_phrase的问题?

Elasticsearchmedcl 回复了问题 • 3 人关注 • 2 个回复 • 62 次浏览 • 6 小时前 • 来自相关话题

es sort 默认值为-9223372036854776000,可以修改吗?

回复

Elasticsearchyuanzhiwei 发起了问题 • 1 人关注 • 0 个回复 • 19 次浏览 • 9 小时前 • 来自相关话题

elasticsearch中使用query后的_score字段来聚合的方法?

Elasticsearchcq1988114 回复了问题 • 4 人关注 • 3 个回复 • 1094 次浏览 • 1 天前 • 来自相关话题

elasticsearch怎样按照某个字段去重

Elasticsearchkepmoving 回复了问题 • 3 人关注 • 2 个回复 • 120 次浏览 • 1 天前 • 来自相关话题

单台es节点cpu彪满,整个集群僵死,api僵死

Elasticsearchkennywu76 回复了问题 • 3 人关注 • 1 个回复 • 193 次浏览 • 5 天前 • 来自相关话题

除了设置mapping为not analyzied,还有其他方法让一个string字段不分词吗?

Elasticsearchancestor 回复了问题 • 6 人关注 • 5 个回复 • 2441 次浏览 • 6 天前 • 来自相关话题

es.5.1.1启动失败

ElasticsearchViento 回复了问题 • 2 人关注 • 1 个回复 • 121 次浏览 • 6 天前 • 来自相关话题

es 5 安装es-hadoop-5 插件

回复

Elasticsearchdddxxx 发起了问题 • 1 人关注 • 0 个回复 • 83 次浏览 • 2017-01-16 16:48 • 来自相关话题

从mongodb全量导入数据

回复

Elasticsearcharsenepark 发起了问题 • 1 人关注 • 0 个回复 • 83 次浏览 • 2017-01-16 12:48 • 来自相关话题

es索引数据时指定节点

Elasticsearchguopengfei 回复了问题 • 3 人关注 • 3 个回复 • 164 次浏览 • 2017-01-14 15:55 • 来自相关话题

条新动态, 点击查看
bsll

bsll 回答了问题 • 2016-11-16 17:14 • 2 个回复 不感兴趣

一个nested字段聚合父子字段

赞同来自:

写了一个demo,不过不知道你是不是这个意思。
DELETE /test_agg
PUT /test_agg
{
   "mappings": {
      "agg_type": {
          "... 显示全部 »
写了一个demo,不过不知道你是不是这个意思。
DELETE /test_agg
PUT /test_agg
{
   "mappings": {
      "agg_type": {
          "properties": {
          "all":{
              "type": "nested",
              "properties": {
                  "parent_id": {
                     "type": "integer"
                  },
                  "child_id": {
                     "type": "integer"
                  }
              }
          }
          }
      }
   }
}

POST /test_agg/agg_type/1
{
    "all":{
        "parent_id":1,
        "child_id":2
        
    }
}
POST /test_agg/agg_type/2
{
    "all":{
        "parent_id":1,
        "child_id":3
        
    }
}
POST /test_agg/agg_type/3
{
    "all":{
        "parent_id":2,
        "child_id":3
        
    }
}
POST /test_agg/_search
POST /test_agg/agg_type/_search
{
    "size": 0, 
   "aggs": {
      "category": {
         "aggs": {
            "term_list": {
               "terms": {
                  "field": "all.parent_id"
               },
               "aggs": {
                  "term_list": {
                     "terms": {
                        "field": "all.child_id"
                     }
                  }
               }
            }
         },
         "nested": {
            "path": "all"
         }
      }
   }
}
 
kennywu76

kennywu76 回答了问题 • 2017-01-04 11:38 • 2 个回复 不感兴趣

新增节点数据均衡.

赞同来自:

对于新增结点是数据的平衡, shard balancing heuristics这个调整比较难以精确控制。 推荐使用索引级别设置: index.routing.allocation.total_shards_per_node  , 这个参数可以控制单个索引在同... 显示全部 »
对于新增结点是数据的平衡, shard balancing heuristics这个调整比较难以精确控制。 推荐使用索引级别设置: index.routing.allocation.total_shards_per_node  , 这个参数可以控制单个索引在同一个结点上最多分配几个shard。 默认是无上限,因此在扩容新结点的时候,很可能一个索引的很多shard分到同一个node。 具体设置多少,需要根据集群结点数量和一个index shard总数量(包含主和副复制片)来定。
 
例如10个node,  index设置 5 primary + 5 replica。 设置index.routing.allocation.total_shards_per_node:1 可以保证这个索引在每个node上只分配一个shard。  这样设置好处是数据分布最均匀, 但是也有负面影响,比如如果有一个node挂了,就会有一个shard无法分配,变成UNASSIGNED状态。  如果设置index.routing.allocation.total_shards_per_node:2 ,则可能数据均衡状态不如设置为1那么理想,但是可以容忍一个node挂掉,因为shard可以再分配到其他node。   这个设置结合shard balancing heuristics做全局调配应该比较理想。

首届ES中文社区技术沙龙【广州站】—企业级搜索引擎与大数据实战分享

Elasticsearchclytie 发表了文章 • 2 个评论 • 1249 次浏览 • 2016-04-18 11:42 • 来自相关话题

从2015年后,大数据被认为是驱动企业变革的推动剂,为经济创新带来新的增量。ElasticSearch(下文简称ES)是当前流行的企业级搜索引擎,它提供了一个分布式多用户能力的全文搜索引擎。简言之,大数据时代ES能够提供简单易用的方式帮助企业从大型数据库中快速提取有效信息进行分析。

2016年首届ES中文社区全国巡回技术沙龙在北京、上海、广州三地召开。ES中文社区携手数说故事共同主办 ElasticSearch技术沙龙-广州站,诚邀您参加交流。

4月23日14:00 - 17:30,广州筑梦咖啡,我们不见不散。


沙龙详情:

1、主办方:
    
 ElasticSearch中文社区    数说故事






2、时间与地点:


4月23日14:00 - 17:30(周六)

广州筑梦咖啡(广州天河区黄埔大道中309号羊城创意产业园(近骏景花园)







沙龙主题:

ElasticSearch技术沙龙—企业级搜索引擎实战与案例分享

 
分享一:你不得不知道的ES的使用经验及优化技巧







赖鸿智

欢聚时代搜索工程师,负责欢聚时代搜索服务

主题简介:

ES使用中掉过的坑以及优化技巧,主要包括:搜索平台的架构,实时大数据分析平台的架构。

 

分享二: 基于父子文档实现的ES关联查询








黄耀鸿

数说故事技术总监,多年大数据开发经验

主题简介:

为你解答在千万级用户和发布的亿级文章内容中,如何利用父子文档,通过一对多的关联查询,实现对内容搜索,对用户分析的场景。

 

分享三:ES实战现场:亿级规模的ES查询优化实战







                                                                                              何金城

塔布高级数据项目经理

主题简介:

在传统家电企业的DMP系统实施实战中ES的一些使用情况及查询优化实践。


活动流程:

14:00-14:30  签到及入场
14:30-14:40  主持人介绍活动
14:40-15:20  赖鸿智    Elasticsearch的一些使用经验及优化技巧
15:20-16:00  黄耀鸿    基于父子文档实现的ES关联查询
16:00-16:40  何金城    亿级规模的ES查询优化实战
16:40-17:10  提问交流   可获精美礼品
17:10-17:30  自由沟通


哪些惊喜:

企业级搜索引擎全程干货的分享

免费领取由ElasticSearch中文社区提供的限量版礼品

有机会参观大数据公司【数说故事】,近距离了解大数据工作流程


报名方式:

本次活动全程免费,欢迎报名
 
报名入口:活动行

活动联系:
联系人:陈小姐
手机:13660037521
邮箱:625802461@qq.com


更多活动详情扫描二维码关注数说故事






(公众号:datastory2015)       查看全部
从2015年后,大数据被认为是驱动企业变革的推动剂,为经济创新带来新的增量。ElasticSearch(下文简称ES)是当前流行的企业级搜索引擎,它提供了一个分布式多用户能力的全文搜索引擎。简言之,大数据时代ES能够提供简单易用的方式帮助企业从大型数据库中快速提取有效信息进行分析。

2016年首届ES中文社区全国巡回技术沙龙在北京、上海、广州三地召开。ES中文社区携手数说故事共同主办 ElasticSearch技术沙龙-广州站,诚邀您参加交流。

4月23日14:00 - 17:30,广州筑梦咖啡,我们不见不散。


沙龙详情:

1、主办方:
    
 ElasticSearch中文社区    数说故事

666666.jpg


2、时间与地点:


4月23日14:00 - 17:30(周六)

广州筑梦咖啡(广州天河区黄埔大道中309号羊城创意产业园(近骏景花园)

搜狗截图16年04月15日1428_1.png



沙龙主题:

ElasticSearch技术沙龙—企业级搜索引擎实战与案例分享

 
分享一:你不得不知道的ES的使用经验及优化技巧


YY.jpg


赖鸿智

欢聚时代搜索工程师,负责欢聚时代搜索服务

主题简介:

ES使用中掉过的坑以及优化技巧,主要包括:搜索平台的架构,实时大数据分析平台的架构。

 

分享二: 基于父子文档实现的ES关联查询


QQ图片20160415200715_副本.jpg



黄耀鸿

数说故事技术总监,多年大数据开发经验

主题简介:

为你解答在千万级用户和发布的亿级文章内容中,如何利用父子文档,通过一对多的关联查询,实现对内容搜索,对用户分析的场景。

 

分享三:ES实战现场:亿级规模的ES查询优化实战



jincheng1.jpg


                                                                                              何金城

塔布高级数据项目经理

主题简介:

在传统家电企业的DMP系统实施实战中ES的一些使用情况及查询优化实践。


活动流程:

14:00-14:30  签到及入场
14:30-14:40  主持人介绍活动
14:40-15:20  赖鸿智    Elasticsearch的一些使用经验及优化技巧
15:20-16:00  黄耀鸿    基于父子文档实现的ES关联查询
16:00-16:40  何金城    亿级规模的ES查询优化实战
16:40-17:10  提问交流   可获精美礼品
17:10-17:30  自由沟通


哪些惊喜:

企业级搜索引擎全程干货的分享

免费领取由ElasticSearch中文社区提供的限量版礼品

有机会参观大数据公司【数说故事】,近距离了解大数据工作流程


报名方式:

本次活动全程免费,欢迎报名
 
报名入口:活动行

活动联系:
联系人:陈小姐
手机:13660037521
邮箱:625802461@qq.com


更多活动详情扫描二维码关注数说故事

【logo】数说故事(datastory2015).jpg


(公众号:datastory2015)      

pinyin分词 match和match_phrase的问题?

回复

Elasticsearchmedcl 回复了问题 • 3 人关注 • 2 个回复 • 62 次浏览 • 6 小时前 • 来自相关话题

elasticsearch中使用query后的_score字段来聚合的方法?

回复

Elasticsearchcq1988114 回复了问题 • 4 人关注 • 3 个回复 • 1094 次浏览 • 1 天前 • 来自相关话题

elasticsearch怎样按照某个字段去重

回复

Elasticsearchkepmoving 回复了问题 • 3 人关注 • 2 个回复 • 120 次浏览 • 1 天前 • 来自相关话题

es.5.1.1启动失败

回复

ElasticsearchViento 回复了问题 • 2 人关注 • 1 个回复 • 121 次浏览 • 6 天前 • 来自相关话题

从mongodb全量导入数据

回复

Elasticsearcharsenepark 发起了问题 • 1 人关注 • 0 个回复 • 83 次浏览 • 2017-01-16 12:48 • 来自相关话题

es索引数据时指定节点

回复

Elasticsearchguopengfei 回复了问题 • 3 人关注 • 3 个回复 • 164 次浏览 • 2017-01-14 15:55 • 来自相关话题

elasticsearch怎么定位到某个位置,然后从此位置删除?(类似于from)

回复

Elasticsearchguopengfei 回复了问题 • 3 人关注 • 2 个回复 • 101 次浏览 • 2017-01-14 15:54 • 来自相关话题

如何清理Elasticsearch特定时间段数据?

回复

Elasticsearchguopengfei 回复了问题 • 5 人关注 • 5 个回复 • 476 次浏览 • 2017-01-14 15:53 • 来自相关话题

elasticsearch5.0集成ik分词问题(type报错)

回复

Elasticsearchmedcl 回复了问题 • 3 人关注 • 2 个回复 • 390 次浏览 • 2017-01-10 10:34 • 来自相关话题

elasticsearch如何精确查询?

回复

Elasticsearchlouisgarcia 回复了问题 • 2 人关注 • 1 个回复 • 150 次浏览 • 2017-01-09 13:39 • 来自相关话题

Elasticsearch 2.x mapping tips

Elasticsearchnodexy 发表了文章 • 2 个评论 • 194 次浏览 • 2017-01-10 21:04 • 来自相关话题

elasticsearch 2.x mapping tips

作者:杨振涛  首发于:Elasticsearch 中文社区  日期:2017-1-10

如果把elasticsearch中的mapping类比为关系型数据库中的schema的话,那么我们可能重点强调了两者之间的共性,而忽略了elasticsearch里mapping很不相同的部分 —— 这恰恰是实践中最容易被坑的地方。这里总结了几点实践中的小心得,希望对你所有帮助。

mapping 基础
创建索引库indexcurl -XPOST "http://192.168.9.19:9200/vivo_vimc"
查看指定索引库的mapping:
curl -XGET "http://192.168.9.19:9200/vivo_ ... ot%3B
 
PS: 这时你获得的结果为空,因为刚建的库,没有mapping信息。

创建索引类型type并指定mapping :curl -XPOST http://192.168.9.19:9200/vivo_vmic/apps/_mapping -d '{
"apps" : {
"properties" : {
"appName" : {
"type" : "string",
"index" : "not_analyzed",
"fields" :{
"cn": {
"type" : "string",
"index" : "analyzed",
"analyzer": "ik"
},
"en": {
"type" : "string",
}
},
"store":"yes"
},
"status" : {
"type" : "boolean"
},
"type" : {
"type" : "integer"
},
"onsaleDate" : {
"type" : "date"
},
}
}
}'
更新mapping (只能增加字段,不能删除字段,也不能修改字段类型,或者说无法增加一个不同类型的同名字段):

增加属性 score:curl -XPOST "http://192.168.9.19:9200/vivo_ ... ot%3B -d '{
"apps": {
"properties": {
"score":{
"type":"float"
}
}
}
}'   
更新成功会返回:{
"acknowledged" : true
}

删除mapping :
2.4版本开始ES已经不支持mapping的删除了。

tip1 dynamic 模式

动态mapping是ES的一个重要特性,这个配置的可选值及含义如下:
true  :支持动态扩展,新增数据有新的属性时,自动添加,索引成功false :不支持动态扩展,新增数据有新的属性时,直接忽略,索引成功strict: 不支持动态扩展,新增数据有新的属性时,会报错,索引失败


tip2 主要数据类型及注意事项
string
    分词和不分词的值都需要,中英文都需要 ,
    长度截取,超长过滤 ,
    大小写问题(不分词时索引数据不会转小写,搜索都会转小写)    
    analyzer: analyzed, not_analyzed, no(表示该属性不能用来做搜索和聚合)
    properties : .raw, .en/.cn
    
date :           如果不明确指定,那么默认的date格式是:"strict_date_optional_time||epoch_millis",这是官网的表述,意思是可以是一个字符串类型的输入,也可以是数值类型的输入,前者可以是日期或者日期加上时间,后者则是毫秒数。关于时区信息:不管业务上是否需要时区信息,我们建议依然保存,以防万一。另外,data类型在明确指定 format 参数时,也有很多坑,对于format: epoch_second, epools_millis ,如果你想用来排序,那么为了性能,我们强烈建议你使用 epoc_second,差距很大哟,你可以亲自做一个对比测试。
 
 long, integer, short, byte, double ,float 希望此类字段参与搜索和聚合的话,就不能设置not_analyzed。
 
boolean, binaryboolean类型比较特殊,在ES里面只定义了false类的值( false, "false", "off", "no", "0", "" , 0, 0.0 ),其他所有都认为是true。实践中,我们建议优先使用 0(编程和性能友好),其次使用 true(兼容json默认的类型)。
 
 ipv4 type:ip 日志分析等最常用的数据类型,注意这里的是ipv4,ipv6目前暂不支持(ES 2.x);赋值时其实传递的是字符串,但ES内部其实保存的是一个long类型。
 
geo type:geo_point , type:geo_shape  LBS服务的必选数据类型,但不建议完全依赖此特性,业务层面要尽可能地缩小范围,或者在使用围栏类功能时,只要业务容忍,使用正方形代替圆形。
 
数组,对象,内嵌将一个复杂对象放在一个属性中,其中数组最常用。
 
completion主要是用来做自动完成和拼写纠错的。


tip3 id设置  

在不设置id的情况下,默认的ES会给一个类似HASH串的随机ID;如果业务上需要且可以保证索引数据的唯一性,也可以使用业务ID作为索引ID,好处就是可以根据业务ID轻松地GET到索引数据,而无需维护索引ID和业务ID的关系。

同时,设置mapping的时候也可以指定ID的生成策略,比如UUID:curl -s -XPUT http://192.168.9.19:9200/vivo_vimc -d '
{
"mappings": {
"apps": {
"_id": {
"path": "uuid"
},
"properties": {
"cnName": {
"type": "string",
"index": "analyzed"
}
}
}
}
}'

tip4 index和type规划

index的别名这个特性就不再强调了,不管是否用到,第一时间设置别名是最佳实践! schema 比较相似的type,放在同一个index里;schema差异非常大的type,建议放在不同的index里;原因是跟搜索引擎的segment以及lucene有关,本质上同一个index里的type底层是同样的存储结构,差异越大意味着type a的属性在type b里大部分都是空值,那么最终会得到一个非常稀疏的矩阵,影响计算效率并浪费存储空间。

关于滚动index的问题,对于日志类的搜索应用,按天或其他维度做滚动index是非常好必要的,这样可以更好地区分冷热数据。比如:
index                        alias
vivo_appstore_log_20160108  
vivo_appstore_log_20160109  vivo_appstore_log
vivo_appstore_log_20160110  vivo_appstore_log
vivo_appstore_log_20160111  vivo_appstore_log
...

如果只需要查询最近3天的数据,那么只需要对3天前的index remove alias即可,然后每天循环滚动。一个细节是,对于这种场景下的索引,写入的时候必须使用原始的index name,而不能使用alias;查询的时候则使用alias。


另一个问题,就是index容量的规划,副本数直接决定需要多少冗余空间;另外,索引数据本身也会有膨胀的现象,尤其是基于中文的全文搜索应用,term集可能会比较大。比如有10000个docs,占用100MB空间时,并不能简单认为100000个docs就占用约1GB。


tip5 测试分词器

如果使用的是基于词典的分词器,比如IK这类,那么线上系统可能会需要按需添加自定义词,或者同义词等,技术上我们可以暴露该类功能给搜索引擎运营人员使用。所以,需要提供一个测试分词器的接口,方便对比和验证。ES默认就提供这样的REST接口的。

按指定分词器分词指定文本:GET /vivo_vimc/apps/_analyze?text=Hello, vivo 移动互联网&analyzer=ik
按指定索引库的属性测试分词效果:GET /vivo_vimc/apps/_analyze
{
"field": "appName",
"text": "Pokemon Go"
}
以上关于 mapping 的几点心得,并非金科玉律,需要根据不同的业务需求场景来区别分析和应对。如果你有更多心得,欢迎回复本文分享。


关于作者:
杨振涛,vivo移动互联网 搜索架构师,关注实时搜索,搜索广告,以及大数据的存储、索引、搜索和可视化。 查看全部
elasticsearch 2.x mapping tips

作者:杨振涛  首发于:Elasticsearch 中文社区  日期:2017-1-10

如果把elasticsearch中的mapping类比为关系型数据库中的schema的话,那么我们可能重点强调了两者之间的共性,而忽略了elasticsearch里mapping很不相同的部分 —— 这恰恰是实践中最容易被坑的地方。这里总结了几点实践中的小心得,希望对你所有帮助。

mapping 基础
创建索引库index
curl -XPOST "http://192.168.9.19:9200/vivo_vimc"

查看指定索引库的mapping:

curl -XGET "http://192.168.9.19:9200/vivo_ ... ot%3B
 


PS: 这时你获得的结果为空,因为刚建的库,没有mapping信息。

创建索引类型type并指定mapping :
curl -XPOST http://192.168.9.19:9200/vivo_vmic/apps/_mapping -d '{
"apps" : {
"properties" : {
"appName" : {
"type" : "string",
"index" : "not_analyzed",
"fields" :{
"cn": {
"type" : "string",
"index" : "analyzed",
"analyzer": "ik"
},
"en": {
"type" : "string",
}
},
"store":"yes"
},
"status" : {
"type" : "boolean"
},
"type" : {
"type" : "integer"
},
"onsaleDate" : {
"type" : "date"
},
}
}
}'

更新mapping (只能增加字段,不能删除字段,也不能修改字段类型,或者说无法增加一个不同类型的同名字段):

增加属性 score:
curl -XPOST "http://192.168.9.19:9200/vivo_ ... ot%3B -d '{
"apps": {
"properties": {
"score":{
"type":"float"
}
}
}
}'
   
更新成功会返回:
{
"acknowledged" : true
}


删除mapping :
2.4版本开始ES已经不支持mapping的删除了。

tip1 dynamic 模式

动态mapping是ES的一个重要特性,这个配置的可选值及含义如下:
  • true  :支持动态扩展,新增数据有新的属性时,自动添加,索引成功
  • false :不支持动态扩展,新增数据有新的属性时,直接忽略,索引成功
  • strict: 不支持动态扩展,新增数据有新的属性时,会报错,索引失败



tip2 主要数据类型及注意事项
  • string

    分词和不分词的值都需要,中英文都需要 ,
    长度截取,超长过滤 ,
    大小写问题(不分词时索引数据不会转小写,搜索都会转小写)    
    analyzer: analyzed, not_analyzed, no(表示该属性不能用来做搜索和聚合)
    properties : .raw, .en/.cn
    
  • date :           如果不明确指定,那么默认的date格式是:"strict_date_optional_time||epoch_millis",这是官网的表述,意思是可以是一个字符串类型的输入,也可以是数值类型的输入,前者可以是日期或者日期加上时间,后者则是毫秒数。关于时区信息:不管业务上是否需要时区信息,我们建议依然保存,以防万一。另外,data类型在明确指定 format 参数时,也有很多坑,对于format: epoch_second, epools_millis ,如果你想用来排序,那么为了性能,我们强烈建议你使用 epoc_second,差距很大哟,你可以亲自做一个对比测试。

 
  •  long, integer, short, byte, double ,float 希望此类字段参与搜索和聚合的话,就不能设置not_analyzed。

 
  • boolean, binaryboolean类型比较特殊,在ES里面只定义了false类的值( false, "false", "off", "no", "0", "" , 0, 0.0 ),其他所有都认为是true。实践中,我们建议优先使用 0(编程和性能友好),其次使用 true(兼容json默认的类型)。

 
  •  ipv4 type:ip 日志分析等最常用的数据类型,注意这里的是ipv4,ipv6目前暂不支持(ES 2.x);赋值时其实传递的是字符串,但ES内部其实保存的是一个long类型。

 
  • geo type:geo_point , type:geo_shape  LBS服务的必选数据类型,但不建议完全依赖此特性,业务层面要尽可能地缩小范围,或者在使用围栏类功能时,只要业务容忍,使用正方形代替圆形。

 
  • 数组,对象,内嵌将一个复杂对象放在一个属性中,其中数组最常用。

 
  • completion主要是用来做自动完成和拼写纠错的。



tip3 id设置  

在不设置id的情况下,默认的ES会给一个类似HASH串的随机ID;如果业务上需要且可以保证索引数据的唯一性,也可以使用业务ID作为索引ID,好处就是可以根据业务ID轻松地GET到索引数据,而无需维护索引ID和业务ID的关系。

同时,设置mapping的时候也可以指定ID的生成策略,比如UUID:
curl -s -XPUT http://192.168.9.19:9200/vivo_vimc -d '
{
"mappings": {
"apps": {
"_id": {
"path": "uuid"
},
"properties": {
"cnName": {
"type": "string",
"index": "analyzed"
}
}
}
}
}'


tip4 index和type规划

index的别名这个特性就不再强调了,不管是否用到,第一时间设置别名是最佳实践! schema 比较相似的type,放在同一个index里;schema差异非常大的type,建议放在不同的index里;原因是跟搜索引擎的segment以及lucene有关,本质上同一个index里的type底层是同样的存储结构,差异越大意味着type a的属性在type b里大部分都是空值,那么最终会得到一个非常稀疏的矩阵,影响计算效率并浪费存储空间。

关于滚动index的问题,对于日志类的搜索应用,按天或其他维度做滚动index是非常好必要的,这样可以更好地区分冷热数据。比如:

index                        alias
vivo_appstore_log_20160108  
vivo_appstore_log_20160109  vivo_appstore_log
vivo_appstore_log_20160110  vivo_appstore_log
vivo_appstore_log_20160111  vivo_appstore_log
...



如果只需要查询最近3天的数据,那么只需要对3天前的index remove alias即可,然后每天循环滚动。一个细节是,对于这种场景下的索引,写入的时候必须使用原始的index name,而不能使用alias;查询的时候则使用alias。


另一个问题,就是index容量的规划,副本数直接决定需要多少冗余空间;另外,索引数据本身也会有膨胀的现象,尤其是基于中文的全文搜索应用,term集可能会比较大。比如有10000个docs,占用100MB空间时,并不能简单认为100000个docs就占用约1GB。


tip5 测试分词器

如果使用的是基于词典的分词器,比如IK这类,那么线上系统可能会需要按需添加自定义词,或者同义词等,技术上我们可以暴露该类功能给搜索引擎运营人员使用。所以,需要提供一个测试分词器的接口,方便对比和验证。ES默认就提供这样的REST接口的。

按指定分词器分词指定文本:
GET /vivo_vimc/apps/_analyze?text=Hello, vivo 移动互联网&analyzer=ik

按指定索引库的属性测试分词效果:
GET /vivo_vimc/apps/_analyze
{
"field": "appName",
"text": "Pokemon Go"
}

以上关于 mapping 的几点心得,并非金科玉律,需要根据不同的业务需求场景来区别分析和应对。如果你有更多心得,欢迎回复本文分享。


关于作者:
杨振涛,vivo移动互联网 搜索架构师,关注实时搜索,搜索广告,以及大数据的存储、索引、搜索和可视化。

ES5.0.0 安装记录

Elasticsearchsunping 发表了文章 • 1 个评论 • 475 次浏览 • 2016-12-05 09:42 • 来自相关话题

创建用户:adduser elasticsearch
可查看创建结果:
##########/etc/passwd
##########/etc/shadow
##########/etc/group
配置环境变量
修改文件:/home/elasticsearch/.profile
追加内容:
export JAVA_HOME=/home/elasticsearch/java/jdk1.8.0_73
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CLASSPATH
export PATH
配置elasticsearch5.0.0
tar -xf elasticsearch-5.0.0.tar.gz -C /home/elasticsearch/
cd /home/elasticsearch/
ln -sv elasticsearch-5.0.0 elasticsearch
mkdir -pv /esdata/elasticsearch/{data,logs}
chown -R elasticsearch.elasticsearch /esdata/elasticsearch
修改ES配置文件
/home/elasticsearch/elasticsearch-5.0.0/config/elasticsearch.yml
http.cors.enabled: true
http.cors.allow-origin: "*"
path.data: /esdata/elasticsearch/data
path.logs: /esdata/elasticsearch/logs
network.host: 192.168.25.57
http.port: 8201
transport.tcp.port: 8301
bootstrap.memory_lock: true
/home/elasticsearch/elasticsearch-5.0.0/config/jvm.options
-Xms8g
-Xmx8g
修改系统参数
/etc/security/limits.conf
elasticsearch soft nproc 65536
elasticsearch hard nproc 65536
elasticsearch soft nofile 65536
elasticsearch hard nofile 65536
elasticsearch - memlock unlimited
/etc/sysctl.conf
vm.max_map_count = 262144
加载更新:sysctl -p
启动ES服务
su - elasticsearch -c "/home/elasticsearch/elasticsearch/bin/elasticsearch &"
  查看全部

创建用户:adduser elasticsearch
可查看创建结果:
##########/etc/passwd
##########/etc/shadow
##########/etc/group
配置环境变量
修改文件:/home/elasticsearch/.profile
追加内容:
export JAVA_HOME=/home/elasticsearch/java/jdk1.8.0_73
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CLASSPATH
export PATH
配置elasticsearch5.0.0
tar -xf elasticsearch-5.0.0.tar.gz -C /home/elasticsearch/
cd /home/elasticsearch/
ln -sv elasticsearch-5.0.0 elasticsearch
mkdir -pv /esdata/elasticsearch/{data,logs}
chown -R elasticsearch.elasticsearch /esdata/elasticsearch
修改ES配置文件
/home/elasticsearch/elasticsearch-5.0.0/config/elasticsearch.yml
http.cors.enabled: true
http.cors.allow-origin: "*"
path.data: /esdata/elasticsearch/data
path.logs: /esdata/elasticsearch/logs
network.host: 192.168.25.57
http.port: 8201
transport.tcp.port: 8301
bootstrap.memory_lock: true
/home/elasticsearch/elasticsearch-5.0.0/config/jvm.options
-Xms8g
-Xmx8g
修改系统参数
/etc/security/limits.conf
elasticsearch soft nproc 65536
elasticsearch hard nproc 65536
elasticsearch soft nofile 65536
elasticsearch hard nofile 65536
elasticsearch - memlock unlimited
/etc/sysctl.conf
vm.max_map_count = 262144
加载更新:sysctl -p
启动ES服务
su - elasticsearch -c "/home/elasticsearch/elasticsearch/bin/elasticsearch &"
 

Pandasticsearch: An Elasticsearch client exposing DataFrame API

Elasticsearchonesuper 发表了文章 • 0 个评论 • 226 次浏览 • 2016-11-08 18:02 • 来自相关话题

https://github.com/onesuper/pandasticsearch
 
# Create a DataFrame object
from pandasticsearch import DataFrame
df = DataFrame.from_es('http://localhost:9200', index='people')

# Print the schema(mapping) of the index
df.print_schema()
# company
# |-- employee
# |-- name: {'index': 'not_analyzed', 'type': 'string'}
# |-- age: {'type': 'integer'}
# |-- gender: {'index': 'not_analyzed', 'type': 'string'}

# Inspect the columns
df.columns
#['name', 'age', 'gender']

# Get the column
df.name
# Column('name')

# Filter
df.filter(df.age < 13).collect()
# [Row(age=12,gender='female',name='Alice'), Row(age=11,gender='male',name='Bob')]

# Project
df.filter(df.age < 25).select('name', 'age').collect()
# [Row(age=12,name='Alice'), Row(age=11,name='Bob'), Row(age=13,name='Leo')]

# Print the rows into console
df.filter(df.age < 25).select('name').show(3)
# +------+
# | name |
# +------+
# | Alice|
# | Bob |
# | Leo |
# +------+

# Sort
df.sort(df.age.asc).select('name', 'age').collect()
#[Row(age=11,name='Bob'), Row(age=12,name='Alice'), Row(age=13,name='Leo')]

# Aggregate
df[df.gender == 'male'].agg(df.age.avg).collect()
# [Row(avg(age)=12)]

# Groupby
df.groupby('gender').collect()
# [Row(doc_count=1), Row(doc_count=2)]

# Groupby and then aggregate
df.groupby('gender').agg(df.age.max).collect()
# [Row(doc_count=1, max(age)=12), Row(doc_count=2, max(age)=13)]

# Convert to Pandas object for subsequent analysis
df[df.gender == 'male'].agg(df.age.avg).to_pandas()
# avg(age)
# 0 12 查看全部
https://github.com/onesuper/pandasticsearch
 
# Create a DataFrame object
from pandasticsearch import DataFrame
df = DataFrame.from_es('http://localhost:9200', index='people')

# Print the schema(mapping) of the index
df.print_schema()
# company
# |-- employee
# |-- name: {'index': 'not_analyzed', 'type': 'string'}
# |-- age: {'type': 'integer'}
# |-- gender: {'index': 'not_analyzed', 'type': 'string'}

# Inspect the columns
df.columns
#['name', 'age', 'gender']

# Get the column
df.name
# Column('name')

# Filter
df.filter(df.age < 13).collect()
# [Row(age=12,gender='female',name='Alice'), Row(age=11,gender='male',name='Bob')]

# Project
df.filter(df.age < 25).select('name', 'age').collect()
# [Row(age=12,name='Alice'), Row(age=11,name='Bob'), Row(age=13,name='Leo')]

# Print the rows into console
df.filter(df.age < 25).select('name').show(3)
# +------+
# | name |
# +------+
# | Alice|
# | Bob |
# | Leo |
# +------+

# Sort
df.sort(df.age.asc).select('name', 'age').collect()
#[Row(age=11,name='Bob'), Row(age=12,name='Alice'), Row(age=13,name='Leo')]

# Aggregate
df[df.gender == 'male'].agg(df.age.avg).collect()
# [Row(avg(age)=12)]

# Groupby
df.groupby('gender').collect()
# [Row(doc_count=1), Row(doc_count=2)]

# Groupby and then aggregate
df.groupby('gender').agg(df.age.max).collect()
# [Row(doc_count=1, max(age)=12), Row(doc_count=2, max(age)=13)]

# Convert to Pandas object for subsequent analysis
df[df.gender == 'male'].agg(df.age.avg).to_pandas()
# avg(age)
# 0 12

在一个Elasticsearch集群中可以使用过个版本数据节点共存吗?

Elasticsearchbong 发表了文章 • 3 个评论 • 401 次浏览 • 2016-07-21 10:35 • 来自相关话题

我们现在Elasticsearch的版本较老,然后数据量比较大,我不知道有平滑升级的方案不?如果有,该怎么做?如果没有,我是否可以把新版本的节点加入到老版本的集群中使用,两个版本共存,然后最后老数据删除,老版本的数据节点也就删除了,想问一下我想的方案是否可行?
 
两个版本共存在一个集群中,会出现哪些可预知的问题?还希望了解的同学回答一下?谢谢! 查看全部
我们现在Elasticsearch的版本较老,然后数据量比较大,我不知道有平滑升级的方案不?如果有,该怎么做?如果没有,我是否可以把新版本的节点加入到老版本的集群中使用,两个版本共存,然后最后老数据删除,老版本的数据节点也就删除了,想问一下我想的方案是否可行?
 
两个版本共存在一个集群中,会出现哪些可预知的问题?还希望了解的同学回答一下?谢谢!

尝试翻译 ElasticSearch 官方文档

Elasticsearchpangpang 发表了文章 • 9 个评论 • 898 次浏览 • 2016-07-08 10:13 • 来自相关话题

最近有翻译官网文档的念头,从上周开始陆陆续续的抽时间翻译,因为工作比较忙,都是晚上熬夜开始翻译的。想要翻译官方文档的原因主要有这几点:
官方文档写的比较好,例子多,容易理解;已有的翻译资料感觉并不是很完善,要么只翻译了一部分,要么版本很旧,很久没人维护(有人翻译 ElasticSearch 权威指南,这个还是不错);自己在工作中经常用到 ElasticSearch,感觉 ElasticSearch 非常强大,帮助我们解决了很多问题,让我有激情去更深入的探索;希望可以帮助到别人;
 
github:  https://github.com/liuzxc/Elasticsearch_reference_cn
 
read online :   https://liuzxc.gitbooks.io/elasticsearch_reference_cn/content/
 
我现在基本上每天翻译 1- 2 节的样子,会持续更新下去,有兴趣的伙伴可以加入进来一起搞! 查看全部
最近有翻译官网文档的念头,从上周开始陆陆续续的抽时间翻译,因为工作比较忙,都是晚上熬夜开始翻译的。想要翻译官方文档的原因主要有这几点:
  1. 官方文档写的比较好,例子多,容易理解;
  2. 已有的翻译资料感觉并不是很完善,要么只翻译了一部分,要么版本很旧,很久没人维护(有人翻译 ElasticSearch 权威指南,这个还是不错);
  3. 自己在工作中经常用到 ElasticSearch,感觉 ElasticSearch 非常强大,帮助我们解决了很多问题,让我有激情去更深入的探索;
  4. 希望可以帮助到别人;

 
github:  https://github.com/liuzxc/Elasticsearch_reference_cn
 
read online :   https://liuzxc.gitbooks.io/elasticsearch_reference_cn/content/
 
我现在基本上每天翻译 1- 2 节的样子,会持续更新下去,有兴趣的伙伴可以加入进来一起搞!

Lucene5.5入门第十篇完结篇——使用Highlighter使关键词高亮

Lucenekl 发表了文章 • 0 个评论 • 478 次浏览 • 2016-06-24 11:27 • 来自相关话题

前言

我们在使用百度和谷歌等搜索引擎的时候,你会发现,搜索引擎会把和我们输入的关键字以红色的字体显示,来突出显示结果的准确性,这就是高亮显示的使用场景

准备

使用Highlighter需要导入相应的jar包,maven项目可以加入如下依赖

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>5.5.0</version>
</dependency>

直接看代码


/**
* @author kl by 2016/3/19
* @boke www.kailing.pub
*/
public class FieldSetBoostTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据
String theme="中国";
String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory=FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
/**
* 创建索引不加权
* @throws Exception
*/
public void Indexer()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}

/**
* 关键命中词高亮输出处理
* @param query
* @param context
* @return
* @throws Exception
*/
public static String getHighlighterString(Query query,String context)throws Exception{
//对促成文档匹配的实际项进行评分
QueryScorer scorer=new QueryScorer(query);
//设置高亮的HTML标签格式
Formatter simpleHTMLFormatter=new SimpleHTMLFormatter("","");
//实例化高亮分析器
Highlighter highlighter=new Highlighter(simpleHTMLFormatter,scorer);
//提供静态方法,支持从数据源中获取TokenStream,进行token处理
TokenStream tokenStream=new CJKAnalyzer().tokenStream("title", new StringReader(context));
return highlighter.getBestFragment(tokenStream, context);
}
@Test
public void searcherTest()throws Exception{
// Indexer();
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher is=new IndexSearcher(reader);
System.out.println("总的文档数:"+reader.numDocs());
QueryParser qp=new QueryParser("title",new CJKAnalyzer());
String q="中国";
Query query=qp.parse(q);
TopDocs tDocs=is.search(query,11);
System.out.println("查询-》"+q+"《-总共命中【"+tDocs.totalHits+"】条结果");
for (ScoreDoc scoredoc:tDocs.scoreDocs){
Document doc = is.doc(scoredoc.doc);
String context=doc.get("title");
if(context!=null){
System.out.println(getHighlighterString(query,context));
}

}
}
}
查询效果如下:

原文地址:http://www.kailing.pub/article/index/arcid/82.html 查看全部
前言

我们在使用百度和谷歌等搜索引擎的时候,你会发现,搜索引擎会把和我们输入的关键字以红色的字体显示,来突出显示结果的准确性,这就是高亮显示的使用场景

准备

使用Highlighter需要导入相应的jar包,maven项目可以加入如下依赖

<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>5.5.0</version>
</dependency>

直接看代码


/**
* @author kl by 2016/3/19
* @boke www.kailing.pub
*/
public class FieldSetBoostTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据
String theme="中国";
String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory=FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
/**
* 创建索引不加权
* @throws Exception
*/
public void Indexer()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}

/**
* 关键命中词高亮输出处理
* @param query
* @param context
* @return
* @throws Exception
*/
public static String getHighlighterString(Query query,String context)throws Exception{
//对促成文档匹配的实际项进行评分
QueryScorer scorer=new QueryScorer(query);
//设置高亮的HTML标签格式
Formatter simpleHTMLFormatter=new SimpleHTMLFormatter("","");
//实例化高亮分析器
Highlighter highlighter=new Highlighter(simpleHTMLFormatter,scorer);
//提供静态方法,支持从数据源中获取TokenStream,进行token处理
TokenStream tokenStream=new CJKAnalyzer().tokenStream("title", new StringReader(context));
return highlighter.getBestFragment(tokenStream, context);
}
@Test
public void searcherTest()throws Exception{
// Indexer();
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher is=new IndexSearcher(reader);
System.out.println("总的文档数:"+reader.numDocs());
QueryParser qp=new QueryParser("title",new CJKAnalyzer());
String q="中国";
Query query=qp.parse(q);
TopDocs tDocs=is.search(query,11);
System.out.println("查询-》"+q+"《-总共命中【"+tDocs.totalHits+"】条结果");
for (ScoreDoc scoredoc:tDocs.scoreDocs){
Document doc = is.doc(scoredoc.doc);
String context=doc.get("title");
if(context!=null){
System.out.println(getHighlighterString(query,context));
}

}
}
}
查询效果如下:

原文地址:http://www.kailing.pub/article/index/arcid/82.html

Lucene5.5入门第九篇——使用searchafter方法实现分页查询

Lucenekl 发表了文章 • 0 个评论 • 501 次浏览 • 2016-06-24 11:25 • 来自相关话题

前言

任何数据量大的情况下,取数据的时候都需要做分页的处理,比如我们百度的时候,结果往往有上千万的结果,而当前呈现在的只有几页的内容,这就是分页的场景,lucene也提供了分页查询的支持

认识searchafter

使用IndexSearcher的searchafter方法可以轻松实现分页查询,如下图



searchafter有多个重载的方法,其中有些searchafter方法Lucene已不推荐使用了,用的多的就searchAfter(final ScoreDoc after, Query query, int numHits)

它有三个形参,分别是

after:上一页最后一个ScoreDoc;

query:query接口实现类的对象,query对象可以通过QueryParser类来创建,也可以自己new Query接口的某一个特定接口实现类;

numHits:每页显示的条数

searchafter官方文档说明地址

重点在下面

/**
* Created by 小陈 on 2016/3/25.
*/
public class IndexerPaging {
//测试数据,模拟数据库表结构
private static String[] ids={"1","2","3","4","5","6"}; //用户ID
private static String [] names={"kl","kl","kl","kl","kl","fds"};
private static String [] describes={"shi yi ge mei nan zi","Don't know","Is an idiot\n","Is an idiot\n","Is an idiot\n","Is an idiot\n"};
//索引存储地址
private static String indexDir="E:\\javaEEworkspace\\LuceneDemo\\LuceneIndex";

/**
* 获取操作索引实体,并添加测试数据
* @param indexDir 索引存储位置
* @return
* @throws Exception
*/
public static void getIndexWriter(String indexDir)throws Exception{
IndexWriterConfig writerConfig=new IndexWriterConfig(getAnalyzer());
IndexWriter indexWriter=new IndexWriter(FSDirectory.open(Paths.get(indexDir)),writerConfig);
Document document=new Document();
//Field.Store.YES或者NO(存储域选项)
//设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
//设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
for(int i=0;i1){
int pageIndexLast=(pageIndex-1)*pageSize-1;
TopDocs hits=searcher.search(query,pageIndexLast);
if(hits.totalHits>=pageIndexLast)
return hits.scoreDocs[pageIndexLast];

}
return null;
}

public static void searcher(String indexDir,String q,int pageIndex,int pageSize)throws Exception{
Directory directory= FSDirectory.open(Paths.get(indexDir));
IndexReader reader= DirectoryReader.open(directory);
IndexSearcher indexSearcher=new IndexSearcher(reader);
QueryParser queryParser=new QueryParser("names",new StandardAnalyzer());
Query query=queryParser.parse(q);
//分页查询
TopDocs hits= indexSearcher.searchAfter(getPageLastScoreDoc(pageIndex,pageSize,query,indexSearcher),query,pageSize);//查询首次的30条
System.out.println("匹配 "+q+"查询到"+hits.totalHits+"个记录");
for (ScoreDoc scoreDoc:hits.scoreDocs){
Document doc=indexSearcher.doc(scoreDoc.doc);
System.out.println(doc.get("describes"));//打印Document的fileName属性
}
reader.close();
directory.close();//关闭连接
}
/**
* 得到默认分词器
* @return
*/
public static Analyzer getAnalyzer(){
return new StandardAnalyzer();
}

@Test
public void Test()throws Exception{
// getIndexWriter(indexDir);
searcher(indexDir,"kl",1,10);//查询测试
}

}原文地址:http://www.kailing.pub/article/index/arcid/80.html 查看全部
前言

任何数据量大的情况下,取数据的时候都需要做分页的处理,比如我们百度的时候,结果往往有上千万的结果,而当前呈现在的只有几页的内容,这就是分页的场景,lucene也提供了分页查询的支持

认识searchafter

使用IndexSearcher的searchafter方法可以轻松实现分页查询,如下图



searchafter有多个重载的方法,其中有些searchafter方法Lucene已不推荐使用了,用的多的就searchAfter(final ScoreDoc after, Query query, int numHits)

它有三个形参,分别是

after:上一页最后一个ScoreDoc;

query:query接口实现类的对象,query对象可以通过QueryParser类来创建,也可以自己new Query接口的某一个特定接口实现类;

numHits:每页显示的条数

searchafter官方文档说明地址

重点在下面

/**
* Created by 小陈 on 2016/3/25.
*/
public class IndexerPaging {
//测试数据,模拟数据库表结构
private static String[] ids={"1","2","3","4","5","6"}; //用户ID
private static String [] names={"kl","kl","kl","kl","kl","fds"};
private static String [] describes={"shi yi ge mei nan zi","Don't know","Is an idiot\n","Is an idiot\n","Is an idiot\n","Is an idiot\n"};
//索引存储地址
private static String indexDir="E:\\javaEEworkspace\\LuceneDemo\\LuceneIndex";

/**
* 获取操作索引实体,并添加测试数据
* @param indexDir 索引存储位置
* @return
* @throws Exception
*/
public static void getIndexWriter(String indexDir)throws Exception{
IndexWriterConfig writerConfig=new IndexWriterConfig(getAnalyzer());
IndexWriter indexWriter=new IndexWriter(FSDirectory.open(Paths.get(indexDir)),writerConfig);
Document document=new Document();
//Field.Store.YES或者NO(存储域选项)
//设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原
//设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完全还原(doc.get)
for(int i=0;i1){
int pageIndexLast=(pageIndex-1)*pageSize-1;
TopDocs hits=searcher.search(query,pageIndexLast);
if(hits.totalHits>=pageIndexLast)
return hits.scoreDocs[pageIndexLast];

}
return null;
}

public static void searcher(String indexDir,String q,int pageIndex,int pageSize)throws Exception{
Directory directory= FSDirectory.open(Paths.get(indexDir));
IndexReader reader= DirectoryReader.open(directory);
IndexSearcher indexSearcher=new IndexSearcher(reader);
QueryParser queryParser=new QueryParser("names",new StandardAnalyzer());
Query query=queryParser.parse(q);
//分页查询
TopDocs hits= indexSearcher.searchAfter(getPageLastScoreDoc(pageIndex,pageSize,query,indexSearcher),query,pageSize);//查询首次的30条
System.out.println("匹配 "+q+"查询到"+hits.totalHits+"个记录");
for (ScoreDoc scoreDoc:hits.scoreDocs){
Document doc=indexSearcher.doc(scoreDoc.doc);
System.out.println(doc.get("describes"));//打印Document的fileName属性
}
reader.close();
directory.close();//关闭连接
}
/**
* 得到默认分词器
* @return
*/
public static Analyzer getAnalyzer(){
return new StandardAnalyzer();
}

@Test
public void Test()throws Exception{
// getIndexWriter(indexDir);
searcher(indexDir,"kl",1,10);//查询测试
}

}
原文地址:http://www.kailing.pub/article/index/arcid/80.html

Lucene5.5入门第八篇——使用QueryParser实现高级查询

Lucenekl 发表了文章 • 0 个评论 • 519 次浏览 • 2016-06-24 11:23 • 来自相关话题

前言

为了解决复杂的查询业务,Lucene给我们提供了一个查询语义分析器,一套完整的语法规则,能够满足大部分的查询需求,而不用关心底层是使用什么Query实现类,就好比写sql一样。 Lucene推荐我们使用QueryParser,而不是各种Query的实现类。但是,QueryParser不能满足所有的查询有求,比如多文档域联合查询 。有时候还是需要使用到Query的相关实现类,好了,下面我们就来看看QueryParser能够解析什么语法,解决什么问题,以及多文档域的查询


直接上代码

每个语法都可以多测试一遍,看看结果,能够加深你的理解,因为这边测试的实在是多,测试结果我就不贴了;

ps:各个查询语义可以交叉使用的,下面代码有部分也用到了,但是这边因为是写的例子,为了能更好的区分每个语义的作用,所有没有做太多的尝试

/**
* @author kl by 2016/3/20
* @boke www.kailing.pub
*/
public class QueryTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据目录
String dataDir="E:\\LuceneTestData";
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new StandardAnalyzer();
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory= FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
@Test
public void TestIndexer()throws Exception{
File[] files= new File(dataDir).listFiles();
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
for(File file:files){
Document doc=new Document();
doc.add(new TextField("filePath",file.getCanonicalPath(), Field.Store.YES));
doc.add(new TextField("context",new FileReader(file)));
writer.addDocument(doc);
}
System.out.println("总共添加了"+writer.numDocs()+"个文档");
writer.close();
}
@Test
public void testSearcher()throws Exception{
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher searcher=new IndexSearcher(reader);
QueryParser queryParser=new QueryParser("context",new StandardAnalyzer());
Query queryw=queryParser.parse("Licensor");//完整匹配分词查询
/**
* 通配符 ?,*的使用
*/
Query queryy=queryParser.parse("Lice?sor");//使用?匹配单个字符查询
Query queryx=queryParser.parse("L*r");//使用*匹配多个字符查询
/**
* 布尔运算AND, OR,NOT,+,-的使用,注意:一定要是大写的AND和OR,NOT
*/
Query queryo=queryParser.parse("Licensor OR ce*");//使用OR联合多关键字查询,也可用空格代替OR
Query queryoo=queryParser.parse(" Licensor ce*");//这个和使用OR一样的效果
Query queryjia=queryParser.parse("+Licensor Wildcard");//+代表必须的条件,搜索文档必须包含Licensor 可能有Wildcard
Query querya=queryParser.parse("Licensor AND ce* AND Licenso?");//使用AND取多个关键字的并集查询
Query queryNot=queryParser.parse("'Lincensor Apache' NOT 'Apache Licensor'");//搜索Lincensor Apache而不是Apache Licensor
Query queryjian=queryParser.parse("'Lincensor Apache' - 'Apache Licensor'");//"-"同NOT的效果一样

/**
* 使用正则表达式查询
*/
Query queryRegular=queryParser.parse("/[Lab]icensor/");//这个匹配Lincensor,aicensor,bicensor分词
Query queryRegularr=queryParser.parse("/[Lab]icenso[a-z]/");//根据需要可以更灵活的使用
/**
* 使用~模糊匹配查询
* 这个要和*号的用法区分下,*号完整通配多个字符查询,而~不是简单的通配,这个模糊匹配和Lucene的评分有关
*/
Query queryFuzzy=queryParser.parse("icensor~");//可以查到Licensor关键字,而queryParser.parse("icensor*")查不到
Query queryFuzzyparam=queryParser.parse("Licens~1");//~后面可加0-2的整数来制定模糊匹配度,默认不加为1
Query queryFuzzyParam=queryParser.parse("Licens cens ~0");//~还可以模糊匹配差异化N字符数的多个关键字
/**
* 范围查询,多用于数字和时间的查询
*/
Query queryRange =queryParser.parse("{abc TO Licens}");//{}abc与Licenszhi间的文件,不包含
Query queryRangex =queryParser.parse("[abc TO Licens]");//{}abc与Licenszhi间的文件,包含本身
/**
* 关键字加权处理查询
*/
//默认为1,可加权可降权,可通过加权处理给匹配的结果排序
Query queryBoosting =queryParser.parse("Licensor Wildcard^4 ");

/**
* Grouping组合查询
*/
Query queryGrouping =queryParser.parse("(+Licensor +Wildcard) AND easier");//可使用()组合多个条件查询

//ps: 查询部分字符需要转义处理,如(+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /)

/**
* 使用MultiFieldQueryParser进行多个文档域查询
*/
Map boost=new HashMap();
boost.put("filePath",1.5F);//设置文档域的权值
boost.put("context",2F);
QueryParser multiField=new MultiFieldQueryParser(new String[]{"filePath","context"},new StandardAnalyzer(),boost);
Query queryq=multiField.parse("lucenetestdata");

TopDocs topDocs= searcher.search(queryq,10);
System.out.println("查询结果共有"+topDocs.totalHits+"条");
for(ScoreDoc scoreDoc:topDocs.scoreDocs){
Document document=searcher.doc(scoreDoc.doc);
System.out.println(document.get("filePath")+"--评分:"+scoreDoc.score);
}
}

}
ps:代码中有大量注释,有些不一定理解到位了,深入了解 请参考官方说明:

https://lucene.apache.org/core ... rches原文地址:http://www.kailing.pub/article/index/arcid/79.html 查看全部
前言

为了解决复杂的查询业务,Lucene给我们提供了一个查询语义分析器,一套完整的语法规则,能够满足大部分的查询需求,而不用关心底层是使用什么Query实现类,就好比写sql一样。 Lucene推荐我们使用QueryParser,而不是各种Query的实现类。但是,QueryParser不能满足所有的查询有求,比如多文档域联合查询 。有时候还是需要使用到Query的相关实现类,好了,下面我们就来看看QueryParser能够解析什么语法,解决什么问题,以及多文档域的查询


直接上代码

每个语法都可以多测试一遍,看看结果,能够加深你的理解,因为这边测试的实在是多,测试结果我就不贴了;

ps:各个查询语义可以交叉使用的,下面代码有部分也用到了,但是这边因为是写的例子,为了能更好的区分每个语义的作用,所有没有做太多的尝试

/**
* @author kl by 2016/3/20
* @boke www.kailing.pub
*/
public class QueryTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据目录
String dataDir="E:\\LuceneTestData";
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new StandardAnalyzer();
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory= FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
@Test
public void TestIndexer()throws Exception{
File[] files= new File(dataDir).listFiles();
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
for(File file:files){
Document doc=new Document();
doc.add(new TextField("filePath",file.getCanonicalPath(), Field.Store.YES));
doc.add(new TextField("context",new FileReader(file)));
writer.addDocument(doc);
}
System.out.println("总共添加了"+writer.numDocs()+"个文档");
writer.close();
}
@Test
public void testSearcher()throws Exception{
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher searcher=new IndexSearcher(reader);
QueryParser queryParser=new QueryParser("context",new StandardAnalyzer());
Query queryw=queryParser.parse("Licensor");//完整匹配分词查询
/**
* 通配符 ?,*的使用
*/
Query queryy=queryParser.parse("Lice?sor");//使用?匹配单个字符查询
Query queryx=queryParser.parse("L*r");//使用*匹配多个字符查询
/**
* 布尔运算AND, OR,NOT,+,-的使用,注意:一定要是大写的AND和OR,NOT
*/
Query queryo=queryParser.parse("Licensor OR ce*");//使用OR联合多关键字查询,也可用空格代替OR
Query queryoo=queryParser.parse(" Licensor ce*");//这个和使用OR一样的效果
Query queryjia=queryParser.parse("+Licensor Wildcard");//+代表必须的条件,搜索文档必须包含Licensor 可能有Wildcard
Query querya=queryParser.parse("Licensor AND ce* AND Licenso?");//使用AND取多个关键字的并集查询
Query queryNot=queryParser.parse("'Lincensor Apache' NOT 'Apache Licensor'");//搜索Lincensor Apache而不是Apache Licensor
Query queryjian=queryParser.parse("'Lincensor Apache' - 'Apache Licensor'");//"-"同NOT的效果一样

/**
* 使用正则表达式查询
*/
Query queryRegular=queryParser.parse("/[Lab]icensor/");//这个匹配Lincensor,aicensor,bicensor分词
Query queryRegularr=queryParser.parse("/[Lab]icenso[a-z]/");//根据需要可以更灵活的使用
/**
* 使用~模糊匹配查询
* 这个要和*号的用法区分下,*号完整通配多个字符查询,而~不是简单的通配,这个模糊匹配和Lucene的评分有关
*/
Query queryFuzzy=queryParser.parse("icensor~");//可以查到Licensor关键字,而queryParser.parse("icensor*")查不到
Query queryFuzzyparam=queryParser.parse("Licens~1");//~后面可加0-2的整数来制定模糊匹配度,默认不加为1
Query queryFuzzyParam=queryParser.parse("Licens cens ~0");//~还可以模糊匹配差异化N字符数的多个关键字
/**
* 范围查询,多用于数字和时间的查询
*/
Query queryRange =queryParser.parse("{abc TO Licens}");//{}abc与Licenszhi间的文件,不包含
Query queryRangex =queryParser.parse("[abc TO Licens]");//{}abc与Licenszhi间的文件,包含本身
/**
* 关键字加权处理查询
*/
//默认为1,可加权可降权,可通过加权处理给匹配的结果排序
Query queryBoosting =queryParser.parse("Licensor Wildcard^4 ");

/**
* Grouping组合查询
*/
Query queryGrouping =queryParser.parse("(+Licensor +Wildcard) AND easier");//可使用()组合多个条件查询

//ps: 查询部分字符需要转义处理,如(+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /)

/**
* 使用MultiFieldQueryParser进行多个文档域查询
*/
Map boost=new HashMap();
boost.put("filePath",1.5F);//设置文档域的权值
boost.put("context",2F);
QueryParser multiField=new MultiFieldQueryParser(new String[]{"filePath","context"},new StandardAnalyzer(),boost);
Query queryq=multiField.parse("lucenetestdata");

TopDocs topDocs= searcher.search(queryq,10);
System.out.println("查询结果共有"+topDocs.totalHits+"条");
for(ScoreDoc scoreDoc:topDocs.scoreDocs){
Document document=searcher.doc(scoreDoc.doc);
System.out.println(document.get("filePath")+"--评分:"+scoreDoc.score);
}
}

}
ps:代码中有大量注释,有些不一定理解到位了,深入了解 请参考官方说明:

https://lucene.apache.org/core ... rches
原文地址:http://www.kailing.pub/article/index/arcid/79.html

Lucene5.5入门第七篇——Lucene索引文档域加权

Lucenekl 发表了文章 • 0 个评论 • 622 次浏览 • 2016-06-24 11:22 • 来自相关话题

前言

就拿百度说事吧,使用百度搜索引擎的时候,你会发现,卧槽,这什么玩意,前面的几个结果根本就不是老子要的东西,都是些推广的内容,而结果匹配度高的还排在老后面去了,百度这铲屎的干嘛吃的!这也不能怪百度,毕竟人家靠推广吃饭的,自然把交了钱的结果权值提高了 !这算文档域加权的使用场景吧

说明

所谓索引域加"权",就是根据需求的不同,对不同的关键值或者不同的关键索引分配不同的权值,因为查询的时候Lucene的评分机制和权值的高低是成正比的,这样权值高的内容更容易被用户搜索出来,而且排在前面。在Lucene3.x版本的时候可以给文档加权,到4.x版本后就取消了给文档加权了,就只有给文档域加权了,如果想达到给文档加权的效果,就要该文档的每个域都加权处理

ps:博主前篇博文谈过IKAnalyzer与paoding中文分词,今天我们使用的是可用于中日韩的二元分词器CJKAnalyzer

闲话少说,直接上代码,看结果


package com.kl.luceneDemo;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Paths;
/**
* @author kl by 2016/3/19
* @boke www.kailing.pub
*/
public class FieldSetBoostTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据
String theme="中国";
String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory=FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
/**
* 创建索引不加权
* @throws Exception
*/
public void Indexer()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}
/**
* 创建索引,指定文档域加权
* @throws Exception
*/
public void IndexerSetBoot()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
if(str.indexOf("是什么")!=-1)
field.setBoost(2);//提高权值
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}
@Test
public void searcherTest()throws Exception{
IndexerSetBoot();
// Indexer();
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher is=new IndexSearcher(reader);
System.out.println("总的文档数:"+reader.numDocs());
QueryParser qp=new QueryParser("title",new CJKAnalyzer());
Query query=qp.parse("中国");
TopDocs tDocs=is.search(query,11);//一次查询多少个结果
System.out.println("总共有【"+tDocs.totalHits+"】条结果");
for (ScoreDoc scoredoc:tDocs.scoreDocs){
Document doc = is.doc(scoredoc.doc);
System.out.println(doc.getField("title").stringValue());
}
}
}
加权和不加权的结果如下



原文地址:http://www.kailing.pub/article/index/arcid/77.html 查看全部
前言

就拿百度说事吧,使用百度搜索引擎的时候,你会发现,卧槽,这什么玩意,前面的几个结果根本就不是老子要的东西,都是些推广的内容,而结果匹配度高的还排在老后面去了,百度这铲屎的干嘛吃的!这也不能怪百度,毕竟人家靠推广吃饭的,自然把交了钱的结果权值提高了 !这算文档域加权的使用场景吧

说明

所谓索引域加"权",就是根据需求的不同,对不同的关键值或者不同的关键索引分配不同的权值,因为查询的时候Lucene的评分机制和权值的高低是成正比的,这样权值高的内容更容易被用户搜索出来,而且排在前面。在Lucene3.x版本的时候可以给文档加权,到4.x版本后就取消了给文档加权了,就只有给文档域加权了,如果想达到给文档加权的效果,就要该文档的每个域都加权处理

ps:博主前篇博文谈过IKAnalyzer与paoding中文分词,今天我们使用的是可用于中日韩的二元分词器CJKAnalyzer

闲话少说,直接上代码,看结果


package com.kl.luceneDemo;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Paths;
/**
* @author kl by 2016/3/19
* @boke www.kailing.pub
*/
public class FieldSetBoostTest {
//索引目录
String indexDir="E:\\LuceneIndex";
//测试数据
String theme="中国";
String []title={"中国是一个伟大的国家","我爱你的的祖国,美丽的中国","是什么,中国令美日等国虎视眈眈"};
/**
* Lucence5.5返回IndexWriter实例
* @param directory
* @return
*/
public IndexWriter getIndexWriter(Directory directory){
Analyzer analyzer=new CJKAnalyzer();//中日韩二元分词
IndexWriterConfig writerConfig=new IndexWriterConfig(analyzer);
IndexWriter writer=null;
try {
writer =new IndexWriter(directory,writerConfig);
}catch (Exception e){
e.printStackTrace();
}
return writer;
}
public Directory getDirctory(String indexDir){
Directory directory=null;
try {
directory=FSDirectory.open(Paths.get(indexDir));
}catch (IOException e){
e.printStackTrace();
}
return directory;
}
/**
* 创建索引不加权
* @throws Exception
*/
public void Indexer()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}
/**
* 创建索引,指定文档域加权
* @throws Exception
*/
public void IndexerSetBoot()throws Exception{
IndexWriter writer=getIndexWriter(getDirctory(indexDir));
Document doc=null;
for(String str:title){
doc=new Document();
//Lucence5.5 Fileld有多个实现,StringFIeld不分词 TextField分词
doc.add(new StringField("theme",theme, Field.Store.YES));
Field field=new TextField("title",str, Field.Store.YES);
if(str.indexOf("是什么")!=-1)
field.setBoost(2);//提高权值
doc.add(field);
writer.addDocument(doc);
}
writer.close();
}
@Test
public void searcherTest()throws Exception{
IndexerSetBoot();
// Indexer();
IndexReader reader= DirectoryReader.open(getDirctory(indexDir));
IndexSearcher is=new IndexSearcher(reader);
System.out.println("总的文档数:"+reader.numDocs());
QueryParser qp=new QueryParser("title",new CJKAnalyzer());
Query query=qp.parse("中国");
TopDocs tDocs=is.search(query,11);//一次查询多少个结果
System.out.println("总共有【"+tDocs.totalHits+"】条结果");
for (ScoreDoc scoredoc:tDocs.scoreDocs){
Document doc = is.doc(scoredoc.doc);
System.out.println(doc.getField("title").stringValue());
}
}
}
加权和不加权的结果如下



原文地址:http://www.kailing.pub/article/index/arcid/77.html

Lucene5.5入门第六篇——Analyzer中文分词

Lucenekl 发表了文章 • 0 个评论 • 708 次浏览 • 2016-06-24 11:18 • 来自相关话题

前言

对于中文分词这个字眼,百科是这么描述的:

中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂的多、困难的多。

简单的说,就是把一个句子拆分成多个词,有废话的赶脚,呵呵

之前几篇博文,笔者都是用的Lucene里的StandardAnalyzer来做的分词处理,虽然在后面的Lucene版本中,

准备工作

这里先把这两个分词器加入到我们的项目中来

IKAnalyzer:IKAnalyzer是一个国人开发的开源的分词工具,下载地址:https://code.google.com/archiv ... e%3D1,GItHub地址:https://github.com/wks/ik-analyzer。推荐到GitHub上下载源码然后自己打包,项目是maven构建的,打成jar,然后在我们的项目中引用。

ps:打包项目的时候记得去掉test

paoding:paoding也是一个开源的i项目,下载地址:https://code.google.com/archiv ... loads,下载下来是一个压缩文件,里面有源码也有打包好可以直接用的jar

ps:下载paoding的时候请自行翻墙吧,这里推荐一个翻墙神器Lantern

进入正文

笔者在测试过程中并不是一番风顺啊,好多坑,下面我们来看看这些坑

IKAnlyzer的问题:

1.最新的项目也是基于Lucene3.0.3版本的,而笔者一直都是使用的最新的Lucene5.5,所以一测试就报了如下的错误

Exception in thread "main" java.lang.VerifyError: class org.wltea.analyzer.lucene.IKAnalyzer overrides final method tokenStream.(Ljava/lang/String;Ljava/io/Reader;)Lorg/apache/lucene/analysis/TokenStream;

解决:笔者有试着将IKAnlyzer项目的Lucene版本换成5.5的重新打包,然后发现行不通,改动的地方太多了,虽然IKAnlyzer项目不大,文件不多。笔者还没达到重写IKAnlyzer项目的能力,有时间可以研究研究源码,最后只有降级自己的Lucene版本了,幸好有maven,降级只要改下pom.xml就行了

paoding的问题

1.项目首先会依赖apache的commons-logging,笔者测试1.1版本通过。

2.然后就是下面的这个了 问题了,其实这个问题paoding自己的使用文档中类似的说明,(Paoding中文分词参考手册.htm)这个文档包含在了下载的压缩包中了

net.paoding.analysis.exception.PaodingAnalysisException: please set a system env PAODING_DIC_HOME or Config paoding.dic.home in paoding-dic-home.properties point to the dictionaries!

解决:就是指定paoding的一个字典文件目录,这个文件在下载下来的压缩包中的dic中,

三种解决方案:

(1).你可以解压缩jar,然后把paoding-dic-home.properties文件中的paoding.dic.home指定你的doc目录,重新压缩,把后缀换成jar就行了。

(2).就是参照官方的说明,把doc目录添加到环境变量中

(3).把doc放在项目目录下

3.paoding还有个问题就是Lucene3.0.3都不兼容了,笔者只好又把Lucene版本降到2.2.0来测试了

越过那些沟沟坎坎终于要见真功夫了,不多说,直接上代码,上图


package com.kl.Lucene;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.TermAttribute;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;
import java.io.StringReader;
/**
* @author kl by 2016/3/14
* @boke www.kailing.pub
*/
public class AnalyzerTest {
//测试数据
public static String testData="中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一" +
"一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。";
/**
* 得到IKAnalyzer分词器
* @return
*/
public static Analyzer getIKAnalyzer(){
return new IKAnalyzer();
}
/**
* 得到Paoding分词器
* @return
*/
public static Analyzer getPaoding(){
return new PaodingAnalyzer();
}
/**
* 测试IKAnalyzer
* @throws Exception
*/
@Test
public void TestIKAnalyzer()throws Exception{
Analyzer analyzer =getIKAnalyzer();
TokenStream tokenStream = analyzer.tokenStream("", new StringReader(testData));
tokenStream.addAttribute(TermAttribute.class);
System.out.println("分词数据:"+testData);
System.out.println("=====IKAnalyzer的分词结果====");
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(new String(termAttribute.term()));
termAttribute.termLength();
}

}
/**
* 测试Paoding
* @throws Exception
*/
@Test
public void TestPaoding()throws Exception{
Analyzer analyzer =getPaoding();
TokenStream ts = analyzer.tokenStream("", new StringReader(testData));
System.out.println("分词数据:"+testData);
System.out.println("=====Paoding的分词结果====");
Token t;
// while ((t = ts.next()) != null) {
// System.out.println(t.termText());
// }
}


}
测试数据:中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。

测试结果如下:





从结果上看,IKAnalyzer和paoding的分词相差无几,IKAnlyzer比paoding的分词粒度更细,这个可以查看他们的分词字典文件去分析

后记:除了上面介绍的两种分词,常用的还有中日韩二元分词器CJKAnalyzer,以及lucene基于中科院分词实现的SmartChineseAnalyzer,其中cjk在lucene-common的jar包里了,SmartChineseAnalyzer需要另外引入jar,如下pom依赖

<!--公共的分词器,包含大多数的语言分词-->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>5.5.0</version>
</dependency>
<!--基于中科院的中文分词-->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>5.5.0</version>
</dependency>


原文地址:[url]http://www.kailing.pub/article/index/arcid/76.html[/url] 查看全部
前言

对于中文分词这个字眼,百科是这么描述的:

中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂的多、困难的多。

简单的说,就是把一个句子拆分成多个词,有废话的赶脚,呵呵

之前几篇博文,笔者都是用的Lucene里的StandardAnalyzer来做的分词处理,虽然在后面的Lucene版本中,

准备工作

这里先把这两个分词器加入到我们的项目中来

IKAnalyzer:IKAnalyzer是一个国人开发的开源的分词工具,下载地址:https://code.google.com/archiv ... e%3D1,GItHub地址:https://github.com/wks/ik-analyzer。推荐到GitHub上下载源码然后自己打包,项目是maven构建的,打成jar,然后在我们的项目中引用。

ps:打包项目的时候记得去掉test

paoding:paoding也是一个开源的i项目,下载地址:https://code.google.com/archiv ... loads,下载下来是一个压缩文件,里面有源码也有打包好可以直接用的jar

ps:下载paoding的时候请自行翻墙吧,这里推荐一个翻墙神器Lantern

进入正文

笔者在测试过程中并不是一番风顺啊,好多坑,下面我们来看看这些坑

IKAnlyzer的问题:

1.最新的项目也是基于Lucene3.0.3版本的,而笔者一直都是使用的最新的Lucene5.5,所以一测试就报了如下的错误

Exception in thread "main" java.lang.VerifyError: class org.wltea.analyzer.lucene.IKAnalyzer overrides final method tokenStream.(Ljava/lang/String;Ljava/io/Reader;)Lorg/apache/lucene/analysis/TokenStream;

解决:笔者有试着将IKAnlyzer项目的Lucene版本换成5.5的重新打包,然后发现行不通,改动的地方太多了,虽然IKAnlyzer项目不大,文件不多。笔者还没达到重写IKAnlyzer项目的能力,有时间可以研究研究源码,最后只有降级自己的Lucene版本了,幸好有maven,降级只要改下pom.xml就行了

paoding的问题

1.项目首先会依赖apache的commons-logging,笔者测试1.1版本通过。

2.然后就是下面的这个了 问题了,其实这个问题paoding自己的使用文档中类似的说明,(Paoding中文分词参考手册.htm)这个文档包含在了下载的压缩包中了

net.paoding.analysis.exception.PaodingAnalysisException: please set a system env PAODING_DIC_HOME or Config paoding.dic.home in paoding-dic-home.properties point to the dictionaries!

解决:就是指定paoding的一个字典文件目录,这个文件在下载下来的压缩包中的dic中,

三种解决方案:

(1).你可以解压缩jar,然后把paoding-dic-home.properties文件中的paoding.dic.home指定你的doc目录,重新压缩,把后缀换成jar就行了。

(2).就是参照官方的说明,把doc目录添加到环境变量中

(3).把doc放在项目目录下

3.paoding还有个问题就是Lucene3.0.3都不兼容了,笔者只好又把Lucene版本降到2.2.0来测试了

越过那些沟沟坎坎终于要见真功夫了,不多说,直接上代码,上图


package com.kl.Lucene;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.TermAttribute;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;
import java.io.StringReader;
/**
* @author kl by 2016/3/14
* @boke www.kailing.pub
*/
public class AnalyzerTest {
//测试数据
public static String testData="中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一" +
"一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。";
/**
* 得到IKAnalyzer分词器
* @return
*/
public static Analyzer getIKAnalyzer(){
return new IKAnalyzer();
}
/**
* 得到Paoding分词器
* @return
*/
public static Analyzer getPaoding(){
return new PaodingAnalyzer();
}
/**
* 测试IKAnalyzer
* @throws Exception
*/
@Test
public void TestIKAnalyzer()throws Exception{
Analyzer analyzer =getIKAnalyzer();
TokenStream tokenStream = analyzer.tokenStream("", new StringReader(testData));
tokenStream.addAttribute(TermAttribute.class);
System.out.println("分词数据:"+testData);
System.out.println("=====IKAnalyzer的分词结果====");
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(new String(termAttribute.term()));
termAttribute.termLength();
}

}
/**
* 测试Paoding
* @throws Exception
*/
@Test
public void TestPaoding()throws Exception{
Analyzer analyzer =getPaoding();
TokenStream ts = analyzer.tokenStream("", new StringReader(testData));
System.out.println("分词数据:"+testData);
System.out.println("=====Paoding的分词结果====");
Token t;
// while ((t = ts.next()) != null) {
// System.out.println(t.termText());
// }
}


}
测试数据:中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。

测试结果如下:





从结果上看,IKAnalyzer和paoding的分词相差无几,IKAnlyzer比paoding的分词粒度更细,这个可以查看他们的分词字典文件去分析

后记:除了上面介绍的两种分词,常用的还有中日韩二元分词器CJKAnalyzer,以及lucene基于中科院分词实现的SmartChineseAnalyzer,其中cjk在lucene-common的jar包里了,SmartChineseAnalyzer需要另外引入jar,如下pom依赖

<!--公共的分词器,包含大多数的语言分词-->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>5.5.0</version>
</dependency>
<!--基于中科院的中文分词-->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>5.5.0</version>
</dependency>


原文地址:[url]http://www.kailing.pub/article/index/arcid/76.html[/url]