ElasticsearchCRUD使用(五)【Elasticsearch中的子文档,父文档】

来源:互联网 发布:阿里云降价 编辑:程序博客网 时间:2024/06/05 13:41

设置文档搜索引擎

AdventureWorks2012用于填充搜索引擎的数据。 可以在这里下载。

以下是使用的传输方法(Entity子对象作为子文档保存在stateprovinces索引中):

public void SaveToElasticsearchStateProvince(){    IElasticsearchMappingResolver elasticsearchMappingResolver = new ElasticsearchMappingResolver();    using ( var elasticsearchContext = new ElasticsearchContext("http://localhost:9200/", new ElasticsearchSerializerConfiguration(elasticsearchMappingResolver,true,true)))    {        elasticsearchContext.TraceProvider = new ConsoleTraceProvider();        using (var databaseEfModel = new SQLDataModel())        {            int pointer = 0;            const int interval = 20;            bool firstRun = true;            int length = databaseEfModel.StateProvince.Count();            while (pointer < length)            {                var collection = databaseEfModel.StateProvince.OrderBy(t => t.StateProvinceID).Skip(pointer).Take(interval).ToList<StateProvince>();                foreach (var item in collection)                {                    var ee = item.CountryRegion.Name;                    elasticsearchContext.AddUpdateDocument(item, item.StateProvinceID);                }                if (firstRun)                {                    elasticsearchContext.SaveChangesAndInitMappingsForChildDocuments();                    firstRun = false;                }                else                {                    elasticsearchContext.SaveChanges();                }                pointer = pointer + interval;            }        }    }}

注意:当您使用代码首先从Entity Framework中的现有数据库导入数据时,ElasticsearchCRUD要求将[key]属性添加到子对象主键。 这些用于为每个文档定义文档_id。 一个文件只能有一个_id!

ElasticSearchProvider for 子文档,父文档

ElasticSearchProvider类实现了Elasticsearch的访问层。 存储层使用ElasticsearchCRUD访问Elasticsearch。 需要为子/父文档配置ElasticsearchSerializerConfiguration类。 为嵌套文档设置默认配置,因此需要更改。 我在默认构造函数中已经构造了所有内容,这也可以与使用构建注入的IoC一起使用。 _context与该类具有相同的生命周期,需要处理。

private const string ConnectionString = "http://localhost:9200/";private readonly IElasticsearchMappingResolver _elasticsearchMappingResolver;private readonly ElasticsearchContext _context;public ElasticSearchProvider(){    _elasticsearchMappingResolver = new ElasticsearchMappingResolver();    _elasticsearchMappingResolver.AddElasticsearchMappingForEntityType(        typeof(Address),         new ElasticsearchMappingAddress()    );    _context = new ElasticsearchContext(        ConnectionString,         new ElasticsearchSerializerConfiguration(            _elasticsearchMappingResolver,            true,            true        )    );}

定义Address 类型的映射是因为这是父索引'stateprovinces'中的子文档。 由于这个原因,默认映射需要被覆盖。 ElasticSearchMapping类可以被继承,只需要实现一个方法:GetIndexForType。 现在Address 类型将被正确映射。

using System;using ElasticsearchCRUD;namespace WebSearchWithElasticsearchChildDocuments.Search{    public class ElasticsearchMappingAddress : ElasticsearchMapping    {        // This address type is a child type form stateprovince in the stateprovinces index        public override string GetIndexForType(Type type)        {            return "stateprovinces";        }    }}

这个类然后在构造函数中添加到上面的Resolver中。

_elasticsearchMappingResolver.AddElasticsearchMappingForEntityType(       typeof(Address),        new ElasticsearchMappingAddress()   );

现在,搜索提供可以实现CRUD功能

public IEnumerable<T> QueryString<T>(string term) {         return _context.Search<T>(BuildQueryStringSearch(term)).PayloadResult.Hits.HitsResult.Select(t =>t.Source).ToList();}private Search BuildQueryStringSearch(string term){    var names = "";    if (term != null)    {        names = term.Replace("+", " OR *");    }    var search = new Search    {        Query = new Query(new QueryStringQuery(names + "*"))    };    return search;}public void AddUpdateDocument(Address address){        // if the parent has changed, the child needs to be deleted and created again. This in not required in this example    _context.AddUpdateDocument(address, address.AddressID, address.StateProvinceID);    _context.SaveChanges();}public void UpdateAddresses(long stateProvinceId, List<Address> addresses){    foreach (var item in addresses)    {        _context.AddUpdateDocument(item, item.AddressID, item.StateProvinceID);    }    _context.SaveChanges();}public void DeleteAddress(long addressId){    _context.DeleteDocument<Address>(addressId);    _context.SaveChanges();}public List<SelectListItem> GetAllStateProvinces(){    var result = from element in _context.Search<StateProvince>("").PayloadResult.Hits.HitsResult.Select(t => t.Source)    select new SelectListItem    {       Text = string.Format("StateProvince: {0}, CountryRegionCode {1}",                    element.StateProvinceCode, element.CountryRegionCode),       Value = element.StateProvinceID.ToString()    };    return result.ToList();}public PagingTableResult<Address> GetAllAddressesForStateProvince(string stateprovinceid, int jtStartIndex, int jtPageSize, string jtSorting){    var result = new PagingTableResult<Address>();    var data = _context.Search<Address>(                    BuildSearchForChildDocumentsWithIdAndParentType(                        stateprovinceid,                         "stateprovince",                        jtStartIndex,                         jtPageSize,                         jtSorting)                );    result.Items = data.PayloadResult.ToList();    result.TotalCount = data.TotalHits;    return result;}// {//  "from": 0, "size": 10,//  "query": {//  "term": { "_parent": "parentdocument#7" }//  },//  "sort": { "city" : { "order": "desc" } }"// }private Search BuildSearchForChildDocumentsWithIdAndParentType(object parentId, string parentType, int jtStartIndex, int jtPageSize, string jtSorting){    var search = new Search    {        From = jtStartIndex,        Size = jtPageSize,        Query = new Query(new TermQuery("_parent", parentType + "#" + parentId))    };    var sorts = jtSorting.Split(' ');    if (sorts.Length == 2)    {        var order = OrderEnum.asc;        if (sorts[1].ToLower() == "desc")        {            order = OrderEnum.desc;        }        search.Sort = CreateSortQuery(sorts[0].ToLower(), order);    }    return search;}public SortHolder CreateSortQuery(string sort, OrderEnum order){    return new SortHolder(        new List<ISort>        {            new SortStandard(sort)            {                Order = order            }        }    );}

_context.Search方法接受在Elasticsearch Search API中直接使用的任何Json字符串。 Elasticsearch提供了如何将这个Json查询放在一起的良好文档。 因为这个例子中的查询非常简单,所以我用StringBuilder添加了它们。 如果需要更复杂的查询,也许您应该使用NEST进行搜索功能。 ElasticsearchCRUD的重点是进行CRUD操作,轻松实现简单,嵌套或父/子文档的数据传输。

SearchController

现在实现后端,需要为视图实现搜索控制器。 jTable表格使用ajax请求直接访问控制器。 jTable要求数据是所需的格式。 该表格执行分页并发送stateprovince文档的parentId(用于Elasticsearch中的地址子文档路由)

using System;using System.Collections.Generic;using System.Web.Mvc;using WebSearchWithElasticsearchChildDocuments.Search;namespace WebSearchWithElasticsearchChildDocuments.Controllers{    [RoutePrefix("Search")]    public class SearchController : Controller    {        readonly ISearchProvider _searchProvider = new ElasticSearchProvider();        [HttpGet]        public ActionResult Index()        {            return View();        }        [Route("Search")]        public JsonResult Search(string term)        {            return Json(_searchProvider.QueryString<StateProvince>(term), "AddressListForStateProvince", JsonRequestBehavior.AllowGet);        }        [Route("GetAddressForStateProvince")]        public JsonResult GetAddressForStateProvince(string stateprovinceid, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = null)        {            try            {                var data = _searchProvider.GetAllAddressesForStateProvince(stateprovinceid, jtStartIndex, jtPageSize, jtSorting);                return Json(new { Result = "OK", Records = data.Items, TotalRecordCount = data.TotalCount });            }            catch (Exception ex)            {                return Json(new { Result = "ERROR", Message = ex.Message });            }        }        [Route("CreateAddressForStateProvince")]        public JsonResult CreateAddressForStateProvince(Address address)        {            try            {                _searchProvider.AddUpdateDocument(address);                return Json(new { Result = "OK", Records = address });            }            catch (Exception ex)            {                return Json(new { Result = "ERROR", Message = ex.Message });            }        }        [HttpPost]        [Route("DeleteAddress")]        public ActionResult DeleteAddress(long addressId, long selectedstateprovinceid)        {            _searchProvider.DeleteAddress(addressId, selectedstateprovinceid);            return Json(new { Result = "OK"});        }    }}

Razor视图如下:

@model WebSearchWithElasticsearchChildDocuments.Models.SearchModel<br/><fieldset class="form">    <legend></legend>    <table width="500">        <tr>            <th></th>        </tr>        <tr>            <td>                <label for="autocomplete">Search: </label>            </td>        </tr>        <tr>            <td>                <input id="autocomplete" type="text" style="width:500px" />            </td>        </tr>    </table></fieldset><div id="addressResultsForStateProvince" /><input name="selectedstateprovinceid" id="selectedstateprovinceid" type="hidden" value="" />@section scripts{    <link href="http://localhost:49907/Content/themes/flat/jquery-ui-1.10.3.min.css" rel="stylesheet" />    <link href="~/Scripts/jtable/themes/jqueryui/jtable_jqueryui.min.css" rel="stylesheet" />    <script type="text/javascript">        $(document).ready(function() {            var updateResults = [];            $("input#autocomplete").autocomplete({                source: function(request, response) {                    $.ajax({                        url: "http://localhost:49907/Search/search",                        dataType: "json",                        data: {                            term: request.term,                        },                        success: function(data) {                            var itemArray = new Array();                            for (i = 0; i < data.length; i++) {                                var labelData = data[i].Name + ", " + data[i].StateProvinceCode + ", " + data[i].CountryRegionCode;                                itemArray[i] = { label: labelData, value: labelData, data: data[i] }                            }                            console.log(itemArray);                            response(itemArray);                        },                        error: function(data, type) {                            console.log(type);                        }                    });                },                select: function(event, ui) {                    $("#selectedstateprovinceid").val(ui.item.data.StateProvinceID);                    $('#addressResultsForStateProvince').jtable('load', {selectedstateprovinceid : ui.item.data.StateProvinceID});                    console.log(ui.item);                }            });                $('#addressResultsForStateProvince').jtable({                    title: 'Address list of selected StateProvince',                    paging: true,                    pageSize: 10,                    sorting: true,                    multiSorting: true,                    defaultSorting: 'City asc',                    actions: {                        deleteAction: function (postData, jtParams) {                            return $.Deferred(function ($dfd) {                                $.ajax({                                    url: 'http://localhost:49907/Search/DeleteAddress?addressId=' + postData.AddressID + "&selectedstateprovinceid=" + $('#selectedstateprovinceid').val(),                                    type: 'POST',                                    dataType: 'json',                                    data: postData,                                    success: function (data) {                                        $dfd.resolve(data);                                    },                                    error: function () {                                        $dfd.reject();                                    }                                });                            });                        },                        listAction: function (postData, jtParams) {                            return $.Deferred(function ($dfd) {                                console.log(jtParams);                                $.ajax({                                    url: 'http://localhost:49907/Search/GetAddressForStateProvince?stateprovinceid=' + $('#selectedstateprovinceid').val(),                                    type: 'POST',                                    dataType: 'json',                                    data: jtParams,                                    success: function (data) {                                        $dfd.resolve(data);                                    },                                    error: function () {                                        $dfd.reject();                                    }                                });                            });                        },                        createAction: function (postData) {                            return $.Deferred(function ($dfd) {                                $.ajax({                                    url: 'http://localhost:49907/Search/CreateAddressForStateProvince?stateprovinceid=' + $('#selectedstateprovinceid').val(),                                    type: 'POST',                                    dataType: 'json',                                    data: postData,                                    success: function (data) {                                        $dfd.resolve(data);                                    },                                    error: function () {                                        $dfd.reject();                                    }                                });                            });                        },                    updateAction: function(postData) {                        return $.Deferred(function ($dfd) {                            $.ajax({                                url: 'http://localhost:49907/Search/CreateAddressForStateProvince?stateprovinceid=' + $('#selectedstateprovinceid').val(),                                type: 'POST',                                dataType: 'json',                                data: postData,                                success: function (data) {                                    $dfd.resolve(data);                                },                                error: function () {                                    $dfd.reject();                                }                            });                        });                    }                },                fields: {                    AddressID: {                        key: true,                        create: true,                        edit: true,                        list: true                    },                    AddressLine1: {                        title: 'AddressLine1',                        width: '20%'                    },                    AddressLine2: {                        title: 'AddressLine2',                        create: true,                        edit: true,                        width: '20%'                    },                    City: {                        title: 'City',                        create: true,                        edit: true,                        width: '15%'                    },                    StateProvinceID: {                        title: 'StateProvinceID',                        create: false,                        edit: false,                        width: '10%'                    },                    PostalCode: {                        title: 'PostalCode',                        create: true,                        edit: true,                        width: '10%'                    },                    ModifiedDate: {                        title: 'ModifiedDate',                        edit: false,                        create: false,                        width: '15%',                        display: function (data) { return moment(data.record.ModifiedDate).format('DD/MM/YYYY HH:mm:ss'); }                    }                }            });        });    </script>}

当autocomplete 选择一个StateProvince项时,它将加载具有子address 项的jTable。 这些项目可以被编辑,删除或新的添加到父StateProvince。 所需的javascript库和css文件都包含在MVC包中。 (jQuery-UI,moment.js和jTable)
这是它的外观:
这里写图片描述

0 0
原创粉丝点击