• 全文检索(elasticsearch入门)


    Elasticsearch篇:

    Elasticsearch是一个采用java语言开发的,基于Lucene构造的开源,分布式的搜索引擎. 设计用于云计算中,能够达到实时搜索,稳定可靠. Elasticsearch的数据模型是JSON. 对于需要分布式需求的这是一个非常好的选择,部署简单,同网段内会自动组成集群服务无需配置。其集成数据库同步插件,不仅支持几乎实时的全文检索服务,还支持距离查询,提供类似类似百度地图离我最近查询。

    官方主页:http://www.elasticsearch.org/ 

    中文词库支持ik:https://github.com/medcl/elasticsearch-analysis-ik

    mmseg :https://github.com/medcl/elasticsearch-analysis-mmseg

    mysql实时自动数据到Elasticsearch 插件:https://github.com/jprante/elasticsearch-river-jdbc
    中文支持版下载:经过作者吐血集成了ik中文分词器与mysql插件elasticsearch-river-jdbc,

    下载地址:http://songwie.com/attached/lucene/elasticsearch-rtf.zip

     spring 对java api 的集成:https://github.com/spring-projects/spring-data-elasticsearch

    目前有好多的提供全文检索引擎服务的项目,选择了一个分布式的可以支持集群模式的使用,Elasticsearch无需部署即可使用,rtf集成版集成了ik中文词库,jdbc-rever等插件。

    基础概念

        Elasticsearch有几个核心概念。从一开始理解这些概念会对整个学习过程有莫大的帮助。
    接近实时(NRT)
            Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒)。    
    集群(cluster)
            一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是 “elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。在 产品环境中显式地设定这个名字是一个好 习惯,但是使用默认值来进行测试/开发也是不错的。     
    节点(node)
            一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况 下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字 对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网 络中的哪些服务器对应于Elasticsearch集群中的哪些节点。     
            一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。    
            在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。    
    索引(index)    
            一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名 字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。   
           在一个集群中,如果你想,可以定义任意多的索引。      
    类型(type)
            在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个 类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类 型,当然,也可以为评论数据定义另一个类型。  
    文档(document)      
            一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以 JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。       
            在一个index/type里面,只要你想,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。        
    分片和复制(shards & replicas)        
            一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。        
            为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。        
            分片之所以重要,主要有两方面的原因:        
                - 允许你水平分割/扩展你的内容容量
                - 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量        
            至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的        
            在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非 常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。        
            复制之所以重要,有两个主要原因:
                - 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
                - 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行            
            总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和 复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变 分片的数量。        
            默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。        

            这些问题搞清楚之后,我们就要进入好玩的部分了...

    curl -<REST Verb> <Node>:<Port>/<Index>/<Type><ID>


    部署:

    Elasticsearch是一个绿色版无需安装即可使用:

    Elasticsearch需要的jdk版本为1.7:

    windows下安装

            一:到官网 http://www.elasticsearch.org/download 或者下载中文集成的版本:https://github.com/medcl/elasticsearch-rtf 

            二:配置系统环境变量:JAVA_HOME: 实际jdk目录,需要1.7及以上版本。

    linux下安装

            默认官方版与windows配置相同。

            中文集成版中:启动插件环境变量配置:

                                    binserviceelasticsearch.conf   配置ES_HOME: set.default.ES_HOME=E:serviceelasticsearch-rtf  

    启动、停止服务

            默认官方版启动:

                                       linux:./bin/elasticsearch start

                                       window:直接运行bin/elasticsearch.bat

             默认官方版停止:

                                       linux:kill 掉elasticsearch 进程。

                                       window:管理启动的elasticsearch.bat 窗口

           

             中文集成版启动与停止:

                                       中文集成版集成了 elasticsearch-servicewrapper这个es插件

                                       linux:

                             ./elasticsearch console  ------前台运行
                             ./elasticsearch start    ------后台运行
                             ./elasticsearch install  -------添加到系统自动启动
                             ./elasticsearch remove   -----取消随系统自动启动
                             ./elasticsearch stop     ------停止
                             ./elasticsearch restart  ------重新启动

                                       window:直接运行elasticsearch.bat

    内存配置情况

          JVM参数与Elasticsearch对照关系

    JVM参数   Elasticsearch默认值 Environment变量
    ‘-Xms 256m ES_MIN_MEM
    ’-Xmx 1g ES_MAX_MEM
    -Xms and -Xmx   ES_HEAP_SIZE 
    -Xmn    ES_HEAP_NEWSIZE
    -XX:MaxDirectMemorySize    ES_DIRECT_SIZE

           官方版配置:

                             linux    配置:elasticsearch.bat 添加 set  Elasticsearch变量=值

                             window配置:elasticsearch.in.sh 添加 set  Elasticsearch变量=值

           中文集成版配置:

                            在service目录下有个elasticsearch.conf配置文件,主要是设置一些java运行环境参数,其中比较重要的是下面的参数:

                            set.default.ES_MIN_MEM=256

                            set.default.ES_MAX_MEM=1024

    群集配置

            常用集群配置参数:config/elasticsearch.yml
            discovery.zen.ping.multicast.enabled: false   设置是否打开多播发现节点,默认是true,如果为false 又没有配置集群列表则代表单机运行。
            discovery.zen.ping.unicast.hosts: ["host1", "host2:port", "host3[portX-portY]"]  设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。

    配置文件介绍

     elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来记录日志的,所以logging.yml里的设置按普通log4j配置文件来设置就行了。
    下面主要讲解下elasticsearch.yml这个文件中可配置的东西。

    cluster.name: elasticsearch
    配置es的集群名称,默认是elasticsearch,es会自动发现在同一网段下的es,如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。
    node.name: "Franz Kafka"
    节点名,默认随机指定一个name列表中名字,该列表在es的jar包中config文件夹里name.txt文件中,其中有很多作者添加的有趣名字。
    node.master: true
    指定该节点是否有资格被选举成为node,默认是true,es是默认集群中的第一台机器为master,如果这台机挂了就会重新选举master。
    node.data: true
    指定该节点是否存储索引数据,默认为true。
    index.number_of_shards: 5
    设置默认索引分片个数,默认为5片。
     
    index.number_of_replicas: 1
    设置默认索引副本个数,默认为1个副本。
    path.conf: /path/to/conf
    设置配置文件的存储路径,默认是es根目录下的config文件夹。
    path.data: /path/to/data
    设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开,例:
    path.data: /path/to/data1,/path/to/data2
    path.work: /path/to/work
    设置临时文件的存储路径,默认是es根目录下的work文件夹。
    path.logs: /path/to/logs
    设置日志文件的存储路径,默认是es根目录下的logs文件夹
    path.plugins: /path/to/plugins
    设置插件的存放路径,默认是es根目录下的plugins文件夹
    bootstrap.mlockall: true
    设置为true来锁住内存。因为当jvm开始swapping时es的效率会降低,所以要保证它不swap,可以把ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值,并且保证机器有足够的内存分配给es。
    同时也要允许elasticsearch的进程可以锁住内存,linux下可以通过`ulimit -l unlimited`命令。
    network.bind_host: 192.168.0.1
    设置绑定的ip地址,可以是ipv4或ipv6的,默认为0.0.0.0。
    network.publish_host: 192.168.0.1
    设置其它节点和该节点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址。
    network.host: 192.168.0.1
    这个参数是用来同时设置bind_host和publish_host上面两个参数。
    transport.tcp.port: 9300
    设置节点间交互的tcp端口,默认是9300。
    transport.tcp.compress: true
    设置是否压缩tcp传输时的数据,默认为false,不压缩。
    http.port: 9200
    设置对外服务的http端口,默认为9200。
    http.max_content_length: 100mb
    设置内容的最大容量,默认100mb
    http.enabled: false
    是否使用http协议对外提供服务,默认为true,开启。
    gateway.type: local
    gateway的类型,默认为local即为本地文件系统,可以设置为本地文件系统,分布式文件系统,hadoop的HDFS,和amazon的s3服务器,其它文件系统的设置方法下次再详细说。
    gateway.recover_after_nodes: 1
    设置集群中N个节点启动时进行数据恢复,默认为1。
    gateway.recover_after_time: 5m
    设置初始化数据恢复进程的超时时间,默认是5分钟。
    gateway.expected_nodes: 2
    设置这个集群中节点的数量,默认为2,一旦这N个节点启动,就会立即进行数据恢复。
    cluster.routing.allocation.node_initial_primaries_recoveries: 4
    初始化数据恢复时,并发恢复线程的个数,默认为4。
    cluster.routing.allocation.node_concurrent_recoveries: 2
    添加删除节点或负载均衡时并发恢复线程的个数,默认为4。
    indices.recovery.max_size_per_sec: 0
    设置数据恢复时限制的带宽,如入100mb,默认为0,即无限制。
    indices.recovery.concurrent_streams: 5
    设置这个参数来限制从其它分片恢复数据时最大同时打开并发流的个数,默认为5。
    discovery.zen.minimum_master_nodes: 1
    设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)
    discovery.zen.ping.timeout: 3s
    设置集群中自动发现其它节点时ping连接超时时间,默认为3秒,对于比较差的网络环境可以高点的值来防止自动发现时出错。
    discovery.zen.ping.multicast.enabled: false
    设置是否打开多播发现节点,默认是true。
    discovery.zen.ping.unicast.hosts: ["host1", "host2:port", "host3[portX-portY]"]
    设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。
    下面是一些查询时的慢日志参数设置
    index.search.slowlog.level: TRACE
    index.search.slowlog.threshold.query.warn: 10s
    index.search.slowlog.threshold.query.info: 5s
    index.search.slowlog.threshold.query.debug: 2s
    index.search.slowlog.threshold.query.trace: 500ms
     
    index.search.slowlog.threshold.fetch.warn: 1s
    index.search.slowlog.threshold.fetch.info: 800ms
    index.search.slowlog.threshold.fetch.debug:500ms
    index.search.slowlog.threshold.fetch.trace: 200ms

       正常启动为:

     对于中文插件的集成与启动插件的集成参考: http://www.51document.com/1364910818272.html

     rtf版本的启动后会有一个界面:

     简单入门使用:

    中文词库 使用参考:https://github.com/medcl/elasticsearch-analysis-mmseg

    https://github.com/medcl/elasticsearch-analysis-ik

    参数说明:curl -<REST Verb> <Node>:<Port>/<Index>/<Type><ID>

    //创建一个名为index的索引库
    curl -XPUT http://localhost:9200/index
     
    //添加索引:
    curl -XPOST http://localhost:9200/index/fulltext/1 -d'
    {"content":"美国留给伊拉克的是个烂摊子吗"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/2 -d'
    {"content":"公安部:各地校车将享最高路权"}
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/3 -d'
    {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/4 -d'
    {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/5 -d'
    {"content":"美国留给伊拉克的是个烂摊子吗","address":"陆家嘴78号"}
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/6 -d'
    {"content":"公安部:各地校车将享最高路权","address":"长吉路78号"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/7 -d'
    {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船","address":"陆家嘴牡丹路78号"}
    '
    curl -XPOST http://localhost:9200/index/fulltext/8 -d'
    {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首","address":"山东路78号"}
    '
    查询:所有字段中包含嫌犯 山东路 的数据
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query" : { "match" : { "_all" : "嫌犯 山东路" }},
    "highlight" : {
    "pre_tags" : ["<hr>", "<hr>"],
    "post_tags" : ["</hr>", "</hr>"],
    "fields" : {
    "content" : {}
    }
    },
    'size': 10,
    "sort": [
    {
    "content":"asc"
    }
    ],
    "highlight": {
    "pre_tags": [
    "<hr>",
    "<hr>"
    ],
    "post_tags": [
    "</hr>",
    "</hr>"
    ],
    "fields": {
    "content": {}
    }
    }
    }
    '
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query" : { "multi_match" : { "query" : "嫌犯 山东路","fields":     [ "content", "address" ] }},
    "highlight" : {
    "pre_tags" : ["<hr>", "<hr>"],
    "post_tags" : ["</hr>", "</hr>"],
    "fields" : {
    "content" : {}
    }
    }
    }
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query" : { "multi_match" : { "query" : "嫌犯 山东路","fields":     [ "content", "address" ], "operator":   "or" ,"minimum_should_match": "50%"}},
    "highlight" : {
    "pre_tags" : ["<hr>", "<hr>"],
    "post_tags" : ["</hr>", "</hr>"],
    "fields" : {
    "content" : {}
    }
    }
    }
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query" : { "more_like_this" : { "like_text" : "嫌犯","fields":     [ "content", "address" ] }},
    "highlight" : {
    "pre_tags" : ["<hr>", "<hr>"],
    "post_tags" : ["</hr>", "</hr>"],
    "fields" : {
    "content" : {}
    }
    }
    }
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query" : { "bool" : { "like_text" : "嫌犯","fields":     [ "content", "address" ] }},
    "highlight" : {
    "pre_tags" : ["<hr>", "<hr>"],
    "post_tags" : ["</hr>", "</hr>"],
    "fields" : {
    "content" : {}
    }
    }
    }
    '
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query": {
    "multi_match": {
    "query": "嫌犯 陆家嘴 山东路",
    "fields": [
    "content",
    "address"
    ],
    "operator": "or",
    "minimum_should_match": "50%"
    }
    },
    "highlight": {
    "pre_tags": [
    "<hr>",
    "<hr>"
    ],
    "post_tags": [
    "</hr>",
    "</hr>"
    ],
    "fields": {
    "content": {}
    }
    }
    }
    '
     
     
     
     
    curl -XPOST http://localhost:9200/index/fulltext/_search  -d'
    {
    "query": {
    "bool": {
    "should": [
    {
    "term": {
    "_all": "嫌犯"
    }
    }
    ]
    }
    },
    "sort": [
    {
    "address":"asc"
    }
    ],
    "highlight": {
    "pre_tags": [
    "<hr>",
    "<hr>"
    ],
    "post_tags": [
    "</hr>",
    "</hr>"
    ],
    "fields": {
    "content": {}
    }
    }
    }
    ' 

    含有距离搜索使用geo_point:

    参考资料:https://github.com/jprante/elasticsearch-river-jdbc/tree/1.0
    curl -XDELETE http://localhost:9200/venue
     
    curl -XPOST http://localhost:9200/venue -d '
    {
    "mappings": {
    "venue": {
    "properties": {
    "name": {
    "type": "string"
    },
    "locations": {
    "type": "geo_point"
    }
    }
    }
    }
    }
    '
     
     
    curl -X POST "http://localhost:9200/venue/venue/" -d'
    {"type":"venue","name":"One","locations":[40.1,-70.1]}'
     
     
     
    curl -X POST "http://localhost:9200/venue/_refresh"
     
    curl -POST 'http://localhost:9200/venue/_search?pretty' -d '
    {
    "query": {
    "filtered": {
    "query": {
    "match" : { "_all" : "One" }
    },
    "filter": {
    "geo_distance": {
    "distance": "60000km",
    "locations": {
    "lat": 5.0,
    "lon": 5.0
    }
    }
    }
    }
    }
    }
    '
     
     
    例子2:
     
     
    curl -XDELETE 'http://localhost:9200/venue/'
    curl -XPUT 'http://localhost:9200/venue/'
     
    curl -XPUT 'http://localhost:9200/venue/tweet/_mapping' -d '
    {
    "tweet" : {
    "properties" : {
    "locations" : {"type" : "geo_point"}
    }
    }
    }'
     
    curl -XPUT 'http://localhost:9200/venue/tweet/1' -d '
    {
    "user": "kimchy",
    "postDate": "2009-11-15T13:12:00",
    "message": "Trying out Elastic Search, so far so good?",
    "locations" : [
    {
    "lat" : 40.00,
    "lon" : 9.00
    }]
    }'
     
    curl -XPUT 'http://localhost:9200/venue/tweet/2' -d '
    {
    "user": "kimchy",
    "postDate": "2009-11-15T13:12:00",
    "message": "Trying out Elastic Search, so far so good?",
    "locations" : [{
    "lat" : 30.00,
    "lon" : 8.00
    }]
    }'
     
    curl -XGET 'http://localhost:9200/venue/tweet/_search' -d '{
    "query": {
    "filtered" : {
    "query" : {
    "match_all" : {}
    },
    "filter" : {
    "geo_distance" : {
    "distance" : "20km",
    "locations" : {
    "lat" : 40.00,
    "lon" : 9.00
    }
    }
    }
    }
    }
    }' 

    从mysql数据库同步数据到elasticsearch使用:

    插件使用介绍:https://github.com/jprante/elasticsearch-river-jdbc'         

                         https://github.com/jprante/elasticsearch-river-jdbc/tree/1.0

    插件需要注意的是jdbc river插件已经对原始的配置做了结构修改,创建index必须按照其api来创建,

    其中index 对应原来的index名字,type是创建的type名字,index_settings 里面是elasticsearch原始配置setting api,

    Type_mapping是elasticsearch原始配置mapping api,如果需要将数据库row 记录id当作索引主键则需要设置 别名,

    例如:select vid as _id ,* from test 

    其他字段类似,如下:

    _index     the index this object should be indexed into
    _type      the type this object should be indexed into
    _id        the id of this object
    _version   the version of this object
    _parent    the parent of this object
    _ttl       the time-to-live of this object
    _routing   the routing of this object
    curl -XDELETE 'localhost:9200/_river/merchant/_meta'
     
    curl -XPOST 'localhost:9200/_river/merchant/_meta' -d '
    {
    flush_interval: "3s",
    type: "jdbc",
    jdbc: {
    url: "jdbc:mysql://xxx:3307/xrdb",
    user: "root",
    password: "root",
    sql: "select * from 数据库表",
    locale: "zh_CN",
    index: "laolaibao",
    type: "merchant",
    index_settings: {
    index: {
    number_of_shards: "2"
    }
    },
    type_mapping: {
    merchant: {
    dynamic: true,
    properties: {
    MERCHANT_NAME: {
    type: "string",
    analyzer: "ik",
    indexAnalyzer: "ik",
    searchAnalyzer: "ik"
    },
    STREET_ADDRESS: {
    type: "string",
    analyzer: "ik",
    indexAnalyzer: "ik",
    searchAnalyzer: "ik"
    },
    LOCATIONS: {
    type: "geo_point"
    }
    }
    }
    }
    }
    }
    '
     
     
    curl -XPOST http://localhost:9200/laolaibao/merchant/_search  -d'
    {
    "query" : { "match" : { "_all" : "宝得 吴淞路258号101室" }},
    'size': 5 ,
    "sort": [
    {
    "address":"asc"
    }
    ],
    "highlight": {
    "pre_tags": [
    "<hr>",
    "<hr>"
    ],
    "post_tags": [
    "</hr>",
    "</hr>"
    ],
    "fields": {
    "content": {}
    }
    }
    }
    '
     
    curl -XPOST http://localhost:9200/laolaibao/merchant/_search  -d'
    {
    "query" : { "multi_match" : { "query" : "宝得莱 吴淞路","fields":     [ "MERCHANT_NAME", "STREET_ADDRESS" ] , "operator":   "or" ,"minimum_should_match": "70%"}},
    'size': 2,
    "sort": [
    {
    "address":"asc"
    }
    ],
    "highlight": {
    "pre_tags": [
    "<hr>",
    "<hr>"
    ],
    "post_tags": [
    "</hr>",
    "</hr>"
    ],
    "fields": {
    "content": {}
    }
    }
    }
    '
     
    curl -XPOST 'http://localhost:9200/laolaibao/merchant/_search?pretty' -d '
    {
    query: {
    filtered: {
    query: {
    match_all: { }
    },
    filter: {
    geo_distance: {
    distance: "50000km",
    LOCATIONS: {
    lat: "37.752258",
    lon: "-121.949886"
    }
    }
    }
    }
    }
    }
    '
    Java api 使用:
    
    官方参考:http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api spring 对java api 的集成:https://github.com/spring-projects/spring-data-elasticsearch
    Pom引入:
    <dependency>
               <groupId>org.elasticsearch</groupId>
               <artifactId>elasticsearch</artifactId>
               <version>1.0.0</version>
           </dependency>
           <dependency>
               <groupId>com.spatial4j</groupId>
               <artifactId>spatial4j</artifactId>
               <version>0.4.1</version>
           </dependency>
           <dependency>
               <groupId>com.vividsolutions</groupId>
               <artifactId>jts</artifactId>
               <version>1.13</version>
               <exclusions>
                   <exclusion>
                       <groupId>xerces</groupId>
                       <artifactId>xercesImpl</artifactId>
                   </exclusion>
               </exclusions>
           </dependency>
     
    Elasticsearch 是原始的官方包,
    spatial4j,jts 是引入未知搜索的第三方包

    使用API进行搜索

    (分场景进行讨论)

             elasticsearch的索引查询主要分为query与filter 两种:query与filter的主要区别在于query会对匹配结果进行评分score,而filter只会对结果做是否匹配判断,不做进一步处理。

             所以如果是强制过滤类的操作可以直接根据fiter过滤掉,而需要对模糊的得分进行score评分,优化索引查询得分,最好做query查询。

             query 由QueryBuilders生成,filter有FilterBuilders生成,

             每个下面索引查询主要分为:termQuery,booleanQuery,matchQuery,rangeQuery,morelikeQuery,prefixQuery等等

                                 过滤也主要分为termFilter,booleanFilter,matchFilter,rangeFilter,morelikeFilter,prefixFilter等等

            查询的创建由SearchRequestBuilder 创建

    1.按关键字搜索。

           查询:QueryBuilder qb = QueryBuilders.multiMatchQuery(
                           queryStr, "MERCHANT_NAME", "STREET_ADDRESS"
                       ).minimumShouldMatch("70%") ; 
                     QueryBuilder qb = QueryBuilders.boolQuery()
                         .must(termQuery("content", "test1"))    
                         .must(termQuery("content", "test4"))    
                         .mustNot(termQuery("content", "test2")) 
                         .should(termQuery("content", "test3"));
            过滤:FilterBuilder filter = FilterBuilders.boolFilter()
                   .must(FilterBuilders.termFilter("MERCHANT_NAME",“宝得莱”));
                     FilterBuilder filter = rangeFilter("age")   
                       .from("10")                           
                      .to("20")                             
                      .includeLower(true)                   
                      .includeUpper(false);                  

    2.关键字搜索+地理位置信息搜索。

     FilterBuilder filter = geoDistanceRangeFilter("pin.location")   
        .point(40, -70)                                           
        .from("200km")                                             
        .to("400km")                                             
        .includeLower(true)                                         
        .includeUpper(false)                                       
        .optimizeBbox("memory")                                   
        .geoDistance(GeoDistance.ARC);        
     QueryBuilder qb = QueryBuilders.multiMatchQuery(
            queryStr, "MERCHANT_NAME", "STREET_ADDRESS"
      ).minimumShouldMatch("70%") ; 
    SearchRequestBuilder request = client.prepareSearch(index) 
     .setSearchType(SearchType.QUERY_THEN_FETCH) 
     .setScroll(new TimeValue(60000)) 
     .setQuery(qb.buildAsBytes()) 
     .setPostFilter(filter) 
     .setTypes(merchant)
     .setFrom(start)
     .setSize(limit) 
     .execute()
     .actionGet(); 

    3.搜索并且排序。

    SortBuilder sort = new FieldSortBuilder("_score").order(SortOrder.DESC).ignoreUnmapped(true);
    SearchRequestBuilder request = client.prepareSearch(index)
     .setSearchType(SearchType.QUERY_THEN_FETCH)
     .setQuery(qb.buildAsBytes())
     .setPostFilter(filter)
     .setTypes(merchant)
     .addSort(sort) 
     .setFrom(start)
     .setSize(limit) 
     .execute() 
     .actionGet(); 


    4.设置搜索权重(或者是索引时建立权重)

    查询时:

           a. 对特殊字段增加权重

    QueryBuilder qb = QueryBuilders.multiMatchQuery(
    queryStr,
    "MERCHANT_NAME", "STREET_ADDRESS","PROVINCE_NAME","CITY_NAME","DISTRICT_NAME"
    )
    .field("MERCHANT_NAME",5f)          //添加字段权重 0-1 代表减弱,大于1代表增加默认1
    .minimumShouldMatch("40%") ;

    BoolFilterBuilder filter = this.parseFilter(mustParams);
    filter = this.parseRangeFilter(filter,rangeParams);

    SearchResponse scrollResp = null;
    SearchRequestBuilder request = client.prepareSearch(index)
    .setSearchType(SearchType.QUERY_THEN_FETCH)
    .setScroll(new TimeValue(60000))
    .setQuery(qb.buildAsBytes())
    .setTypes(merchant)
    .addHighlightedField("MERCHANT_NAME")
    .setHighlighterPreTags("<B>" )
    .setHighlighterPostTags("<B>" )
    .setFrom(start)
    .setSize(limit);

    b. 通过需改score算法修改得分规则:

         

    创建索引时:

        a. 创建索引时通过在数据json中添加权重boost:1.2 来提高数据索引权重,_boost默认=1,大于1是提高权重,小于1是降低权重。

          例:curl -XPOST http://localhost:9200/index/fulltext/19 -d' {_boost:11,"content":"公安部:中国驻洛杉矶领事馆遭亚裔男子枪击"} '  

        b. 通过创建mapping 是对某列单独提高搜索权重,设置boost。

          例: 

    { mappings: { laolaibao: { _all: { indexAnalyzer: "ik",  searchAnalyzer: "ik",  term_vector: "no",  store: "false" }, properties: { MERCHANT_NAME: { type: "string",  store: "no",  term_vector: "with_positions_offsets",  indexAnalyzer: "ik",  searchAnalyzer: "ik",  include_in_all: "true",  boost: 8 } } } } }

    http://songwie.com/articlelist/43

  • 相关阅读:
    空值判断(is not null)
    http协议相关面试题
    Linux基本面试题。(感觉也就这几个了)
    1、了解django运行流程
    python笔试常见题
    selenium中一些可能用到的js操作
    元素判断
    二次封装
    关于在阿里云上面安装mysql遇到的一些问题。
    linux常用的一些基本命令
  • 原文地址:https://www.cnblogs.com/softidea/p/6119362.html
Copyright © 2020-2023  润新知