2018-11-17 Elasticsearch .NET client 笔记

问题描述

  1. 使用Elasticsearch .NET client 创建ES的实例,并导入Shapefile数据建全文索引和空间索引。
  2. Shapefile为地址点数据,需要对指定的字段进行全文检索(分词、拼音),支持范围搜索

ES服务端配置

  1. ES的版本为6.3.0
  2. 采用ik插件进行分词
  3. 采用pinyin插件进行拼音模块
  4. 使用postman测试
#创建实例
PUT http://localhost:9200/test_index
{
    "index":{
      "analysis":{
        "analyzer":{
           "ik_pinyin_analyzer":{
            "type":"custom",
            "tokenizer":"ik_smart",
            "filter":"pinyin_filter"
          }
        },
        "filter":{
          "pinyin_filter":{
            "type":"pinyin",
            "keep_first_letter": false
          }
        }
      }   
}
    
}
#返回结果
//////////////////返回结果////////////////////////
{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "test_index"
}

///////////////////返回结果//////////////////////
#配置Mapping
PUT http://localhost:9200/test_index/_mapping/test_type
{
  "properties": {
    "testfield":{
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart",
      "fields": {
        "my_pinyin":{
          "type":"text",
          "analyzer": "ik_pinyin_analyzer",
          "search_analyzer": "ik_pinyin_analyzer"
        }
      }
    }
  }
}

#返回结果
//////////////////返回结果////////////////////////
{
    "acknowledged": true
}
//////////////////返回结果////////////////////////
#索引文档

POST http://localhost:9200/test_index/test_type
{
  "testfield":"今天天气不错"
}
#返回结果
//////////////////返回结果////////////////////////
{
    "_index": "test_index",
    "_type": "test_type",
    "_id": "tjDRIWcBQbCTUJC9qxCs",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}
//////////////////返回结果////////////////////////
#搜索文档(中文)
POST http://localhost:9200/test_index/test_type/_search
{
  "query":{
    "match": {
      "testfield": "天气"
    }
  }
}
#返回结果
//////////////////返回结果////////////////////////
{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.2876821,
        "hits": [
            {
                "_index": "test_index",
                "_type": "test_type",
                "_id": "tzDYIWcBQbCTUJC9HRBn",
                "_score": 0.2876821,
                "_source": {
                    "testfield": "今天天气不错"
                }
            }
        ]
    }
}
//////////////////返回结果////////////////////////


#搜索文档(拼音)
POST http://localhost:9200/test_index/test_type/_search
{
  "query":{
    "match": {
      "testfield.my_pinyin": "tianqi"
    }
  }
}
#返回结果
//////////////////返回结果////////////////////////
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.68324494,
        "hits": [
            {
                "_index": "test_index",
                "_type": "test_type",
                "_id": "tzDYIWcBQbCTUJC9HRBn",
                "_score": 0.68324494,
                "_source": {
                    "testfield": "今天天气不错"
                }
            }
        ]
    }
}
//////////////////返回结果////////////////////////

通过以上测试,可以确定ES的服务端功能可以实现,接下来就是使用.NET客户端进行调用

ES客户端配置

  1. vs2015 .net 4.6.1
  2. nuget 安装 Es.net client

首先建立连接,本机测试是单机部署,所以连接比较简单

            var uris = new[] { new Uri("http://localhost:9200") };
            var connectionPool = new SniffingConnectionPool(uris);
            var settings = new ConnectionConfiguration(connectionPool);
            var lowlevelClient = new ElasticLowLevelClient(settings);

ElasticLowLevelClient这个类里面封装了各种操作,只需要构建请求体PostData就行。官方给出的方法是利用匿名对象或者字符串,在构造复杂对象的时候单独使用可能不够方便,可以根据情况自行调整。例如,导入的shapefile有多个字段需要分词,应当如何动态生成Mappings,还有在用bulk批量导入的时候,文档应该如何转成Postdata的格式。

目标1 根据需要分词的字段和固定的空间位置字段生成请求体

分析如下:层次较多,且有动态生成的内容,使用字符串format的方法比较难控制。所以固定属性名的采用匿名对象的方式,而属性名动态生成的部分,用Dictionary来解决。

ps C# 中 string.format()的字符串中如果本来有“{}”,需要写成“{{}}”

 public static object setMapping(List splitFields)
        {
            #region 配置模板
            var pinyin_filter_TEMPLATE = new
            {
                type = "pinyin",
                keep_first_letter = false
            };
            var ik_pinyin_analyzer_TEMPLATE = new
            {
                type = "custom",
                tokenizer = "ik_smart",
                filter = "pinyin_filter"
            };
            var splitField_TEMPLATE = new
            {
                type = "text",
                analyzer = "ik_max_word",
                search_analyzer = "ik_max_word",
                fields = new
                {
                    my_pinyin = new
                    {
                        type = "text",
                        analyzer = "ik_pinyin_analyzer",
                        search_analyzer = "ik_pinyin_analyzer"
                    }
                }
            };
            var shape_TEMPLATE = new
            {
                type = "geo_point"

            };

            var settings = new
            {
                index = new
                {
                    analysis = new
                    {
                        analyzer = new
                        {
                            ik_pinyin_analyzer = ik_pinyin_analyzer_TEMPLATE
                        },
                        filter = new
                        {
                            pinyin_filter = pinyin_filter_TEMPLATE
                        }
                    }
                }
            };
            #endregion

            var propertiesBody = new Dictionary();
            // 分词字段
            foreach (string field in splitFields)
            {
                propertiesBody.Add(field, splitField_TEMPLATE);
            }
            // 空间位置字段
            propertiesBody.Add("shape", shape_TEMPLATE);

            var properties = new
            {
                properties = propertiesBody
            };
            var indexNameTEMPLATE = new Dictionary();
            // type "addorpoi" ,可以用变量代替,一般type是自定义的
            indexNameTEMPLATE.Add("addorpoi", properties);

            var mappings = indexNameTEMPLATE;

            var settinMapping = new
            {
                settings = settings,
                mappings = mappings
            };

            return settinMapping;
        }
目标2 根据空间位置和指定间距进行地址搜索

分析如下:搜索的请求体固定,只要换参数即可,也可以使用字符串,虽然不太简洁,但是也是一种思路。
原有的查询字符串

{
"query":{
    "bool":{
        "must":{
            "match_all":{}
            },
        "filter":{
            "geo_distance":{
                "distance":"100m",
                "shape":"30.6321727220001,120.308015149"
            }
            }
        }
    }

}

使用https://www.sojson.com/yasuoyihang.html提供的压缩转义工具,获得一行转义的json字符串,再用文本把{换成{{ 同时}换成}},然后把参数扣掉换成format需要的形式。

var searchStr = string.Format(searchTemplate, "30.6321727220001,120.308015149", "100");
vat postbody = PostData.String(searchStr);

你可能感兴趣的:(2018-11-17 Elasticsearch .NET client 笔记)