opensearch-project / opensearch-net

OpenSearch .NET Client
Apache License 2.0
105 stars 49 forks source link

[BUG] Create Mapping Index error: illegal_state_exception #224

Closed liguobao closed 1 year ago

liguobao commented 1 year ago

What is the bug?

I try to migration "elastis 6.8.14" to OpenSearch 2.3.0 Version,

use Mapping func createIndex, the server response 400 err.

Error like it.

- [1] HealthyResponse: Node: https://amaaaaaaquidwmyaaxnatcn3lyl3dmnigrvf27vj76rldv6fzrojqj43wlna.opensearch.us-chicago-1.oci.oraclecloud.com:9200/ Took: 00:00:00.0107540
# Request:
{"index":{"_id":"452e6028-5665-40ad-9b8e-aed105015852","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"topClass":0,"isPay":false,"tags":["Eastern Fantasy","Tragic Past","Hiding True Abilities","Special Abilitie","FantasyAction","Wars","Saint","Monsters","Immortals","Friendship","Martial arts","Teamwork","Xianxia","Ancient ChinaFanfiction","Fantasy World","Wuxia","Spirits","Revenge","Legend","Weak to Strong","Betrayal","Destiny"],"aliases":["修罗武神"],"ratingCount":20,"waitingReleaseCoun
t":3890,"borrowFromChapters":null,"borrowToChapters":null,"author":{"name":"","enName":"","authorId":null,"updateTime":"2021-08-12T10:21:44","createTime":"2019-07-17T06:35:54","id":"3b9202c7-9b64-4522-8580-401c7cfd38ea"},"genres":[],"source":null,"translator":{"groupName":"1231015","GroupIco":"testgroup","qualityBookIntro":"testquality","qualityChapterIntro":"testchapter","originChapterIntro":"testorigin","updateTime":"2021-10-15T07:51:09.740474","createTime":"2020-05-06T05:56:09.073","id":""},"trend":{"bookId":"452e6028-5665-40ad-9b8e-aed105015852","weekTrend":1,"monthTrend":1231942,"exposureTrend":177055,"readingTrend":1,"updateTime":"2023-05-22T00:20:44","createTime":"2018-11-07T00:49:26","id":"57f62c85-acb2-4c16-96c7-8d490ec2c70c"},"bricksTrend":{"bookId":"452e6028-5665-40ad-9b8e-aed105015852","weekTrend":64,"monthTrend":76,"updateTime":"2023-05-22T00:12:41","createTime":"2023-05-22T00:12:41","id":"d97e5b7d-fed2-482b-8bc6-9c328d3a9ea0"},"releasePlan":{"times":["08:00","18:00"],"bookId":"452e6028-5665-40ad-9b8e-aed105015852","releaseType":"cron","startDate":"2019-06-17T00:00:00","endDate":"2020-07-17T00:00:00","periodReleaseCount":2,"voteEnabled":false,"cronEnabled":false,"maxVoteChapterCount":10,"currentVoteReleaseCount":0,"voteRequestedNum":50,"voteReleaseNum":1,"releaseCycleDays":0,"updateTime":"2019-08-30T03:09:11.971229","createTime":"2019-06-26T13:49:23.617237","id":"eb9691a0-8f28-4a3b-8c44-9e6473874402"},"promotions":[],"premiumLibrary":null,"strategyId":"f3c2c02f-0976-479a-8aef-41b75b7b4ab3","pricingStrategyId":null,"lastChapterTime":"2019-06-13T16:56:40","isOriginal":false,"onlyRechargePurchase":false,"join":"book-base","bookSeries":null,"seriesId":null,"seriesOrder":null,"seriesBookJoinTime":null,"authorId":"3b9202c7-9b64-4522-8580-401c7cfd38ea","isCopyrightAuthorized":"1","cover":"https://babelchain-discourse-upload.s3.dualstack.us-west-2.amazonaws.com/original/3X/1/8/18158258d760dc1227d1aa67d4d2bd8355708a6e.jpeg","volume":"V1","editorId":null,"name":"Martial God Asura","originRefId":"a2e61ff1-2e17-
4ef9-a2ec-d22faad80305","publisherId":"810b6a99-0c43-4447-b248-5198d65580dc","publishTime":"0001-01-01T00:00:00","synopsis":"One night a mysterious and unexplained phenomenon occurs in the nine provinces. Five years later Chu Feng, a regular outer disciple of the Azure Dragon school, awakens one of the mysterious nine lightning beasts. And discovers an egg sealed inside him. \nFrom there we follow Chu Feng as he crosses the continent, beating up strongest senior brothers, raiding tombs, destroying sects and of course as he conquers beauties.\n","tag":"|Eastern Fantasy|Tragic Past|Hiding True Abilities|Special Abilitie|FantasyAction|Wars|Saint|Monsters|Immortals|Friendship|Martial arts|Teamwork|Xianxia|Ancient ChinaFanfiction|Fantasy World|Wuxia|Spirits|Revenge|Legend|Weak to Strong|Betrayal|Destiny|","translatorId":"","enSerial":"ongoing","status":0,"alias":"|修罗武神|","canonicalName":"martial-god-asura","cnName":"修罗武神","copyright":"磨铁","historyCanonicalName":"martial-god-asura","serial":"c","subTitle":"The only way to save his mother was becoming a martial god asura.","ratingNum":8.800000000000000000000000000,"releasedChapterCount":80,"cpEnCompanyName":"","corpusBookId":361,"corpusProjectId":3946,"corpusI18NId":361,"sensitivityRating":"","richSynopsis":"","targetAudience":1,"subway":null,"languageCode":"en","countryCode":"US","updateTime":"2022-06-27T10:15:27","createTime":"2019-07-19T02:35:34","id":"452e6028-5665-40ad-9b8e-aed105015852"}
{"index":{"_id":"37cb21f9-fcaf-4a1c-ae9e-6887f7a6e972","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"strategy","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"strategyId":"f3c2c02f-0976-479a-8aef-41b75b7b4ab3","strategy":{"name":"所有平台 全区上架","isNotFound":false,"offlineReason":"所有平台 全区上架","isShowOfflineReason":true,"remark":"全区上架策略7,30日","includeCounties":["CN","US","ID","IN","BR","PH","TH","MY","RU","PE","MX","GB","FR","CA","AU","SG","TR","IT","CO","AR","DE","ES","MN","KP","KR","VN","LA","KH","MM","BN","SG","TL","NP","BT","BD","PK","LK","MV","KZ","KG","TJ","UZ","TM","AF","IQ","IR","SY","JO","LB","IL","PS","SA","BH","QA","KW","AE","OM","YE","GE","AM","AZ","CY","JP","SE","NO","IS","DK","FO","EE","LV","LT","BY","UA","MD","PL","CZ","SK","HU","AT","CH","LI","IE","NL","BE","LU","MC","RO","BG","RS","MK","AL","GR","SI","HR","VA","SM","MT","PT","AD","EG","LY","SD","TN","DZ","MA","ET","ER","SO","DJ","KE","TZ","UG","RW","BI","SC","TD","CF","CM","GQ","GA","CG","CD","ST","MR","EH","SN","GM","ML","BF","GN","GW","CV","SL","LR","CI","GH","TG","BJ","NE","ZM","AO","ZW","MW","MZ","BW","NA","ZA","SZ","LS","MG","KM","MU","SH","NZ","PG","SB","VU","FM","MH","PW","NR","KI","MP","TV","WS","FJ","GU","NC","PF","PN","WF","NU","TK","AS","MP","GL","GT","BZ","SV","HN","NI","CR","PA","BS","CU","JM","HT","AG","KN","DM","LC","VC","GD","BB","TT","PR","VG","VI","AI","GP","MQ","AW","TC","KY","BM","VE","GY","GF","SR","EC","BO","CL","UY","PY","UNKOWN"],"showLocations":["list","search","chapter","library","book"],"platforms":["web","ios","android"],"isAllPlatforms":null,"updateTime":"2019-07-30T07:21:36.687607","createTime":"2019-07-30T07:21:36.687606","id":"f3c2c02f-0976-479a-8aef-41b75b7b4ab3"},"enabledExternalLink":false,"showText":"","externalLink":"","updateTime":"2020-10-13T06:07:57.050822","createTime":"2020-10-13T06:07:57.050699","id":"37cb21f9-fcaf-4a1c-ae9e-6887f7a6e972"}
{"index":{"_id":"c047d045-86e8-4ba6-9543-45fe059fa5fb","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"stop-notice","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"notice":"停更","startTime":null,"endTime":null,"isShowNotice":true,"enabled":false,"isAlways":true,"enabledExternalLink":false,"showText":"","externalLink":"","annnotationId":"22488d4c-d69d-4552-9ec6-e449559840ce","updateTime":"2019-10-24T07:03:11.876316","createTime":"2019-09-25T10:00:20.203514","id":"c047d045-86e8-4ba6-9543-45fe059fa5fb"}
{"index":{"_id":"3226a86a-473e-4a7a-8cce-7d51bd47a723","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"3226a86a-473e-4a7a-8cce-7d51bd47a723","id":"91267e17-87ad-47fe-980d-05870da88620","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3970","num":39700000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3970/62803","translatorId":null,"publishTime":"2019-06-13T16:56:40","canonicalName":"c3970","isPublish":true,"summary":"The six great powers were an alliance. Even if they had grudges, they would still have to show mercy.\n\nAt the very least, he would have to show mercy here.\n\nAfter all, there were so many people watchi","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1450,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
{"index":{"_id":"507ac681-1b80-482b-bdb8-9511e318e0b3","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"507ac681-1b80-482b-bdb8-9511e318e0b3","id":"91267e17-87ad-47fe-980d-05870da88620","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3970","num":39700000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3970/62803","translatorId":null,"publishTime":"2019-06-13T16:56:40","canonicalName":"c3970","isPublish":true,"summary":"The six great powers were an alliance. Even if they had grudges, they would still have to show mercy.\n\nAt the very least, he would have to show mercy here.\n\nAfter all, there were so many people watchi","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1450,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
{"index":{"_id":"5596112c-d11c-4bca-aca8-cd5393f3cad1","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"5596112c-d11c-4bca-aca8-cd5393f3cad1","id":"9126
7e17-87ad-47fe-980d-05870da88620","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3970","num":39700000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3970/62803","translatorId":null,"publishTime":"2019-06-13T16:56:40","canonicalName":"c3970","isPublish":true,"summary":"The six great powers were an alliance. Even if they had grudges, they would still have to show mercy.\n\nAt the very least, he would have to show mercy here.\n\nAfter all, there were so many people watchi","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1450,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
{"index":{"_id":"dd697927-fa0a-4e07-ac85-610c70aae618","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"dd697927-fa0a-4e07-ac85-610c70aae618","id":"91267e17-87ad-47fe-980d-05870da88620","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3970","num":39700000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3970/62803","translatorId":null,"publishTime":"2019-06-13T16:56:40","canonicalName":"c3970","isPublish":true,"summary":"The six great powers were an alliance. Even if they had grudges, they would still have to show mercy.\n\nAt the very least, he would have to show mercy here.\n\nAfter all, there were so many people watchi","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1450,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
{"index":{"_id":"df9d5b21-4223-43bb-9fe3-53ea0386463a","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"df9d5b21-4223-43bb-9fe3-53ea0386463a","id":"dc573695-d215-42a4-b4f0-4635130c7da8","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3964","num":39640000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3964/63342","translatorId":null,"publishTime":"2019-06-08T18:22:39","canonicalName":"c3964","isPublish":true,"summary":"Boom — —\n\nBoom — —\n\nBoom — —\n\nBoom — —\n\nJust as the crowd was puzzled, a bolt of lightning struck down from the sky.\n\nThe purple lightning was extremely fierce. It had a total of twelve lightning drag","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1550,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
{"index":{"_id":"91267e17-87ad-47fe-980d-05870da88620","routing":"452e6028-5665-40ad-9b8e-aed105015852"}}
{"join":{"name":"last-chapter","parent":"452e6028-5665-40ad-9b8e-aed105015852"},"applicationControlId":"91267e17-87ad-47fe-980d-05870da88620","id":"91267e17-87ad-47fe-980d-05870da88620","bookId":"452e6028-5665-40ad-9b8e-aed105015852","name":"C3970","num":39700000,"hasContent":true,"url":"http://discourse/t/martial-god-asura-c3970/62803","translatorId":null,"publishTime":"2019-06-13T16:56:40","canonicalName":"c3970","isPublish":true,"summary":"The six great powers were an alliance. Even if they had grudges, they would still have to show mercy.\n\nAt the very least, he would have to show mercy here.\n\nAfter all, there were so many people watchi","chapterIndex":0,"brick":0,"originBrick":0,"discountRate":0.0,"type":"babelchain","words":1450,"isPremiumFree":false,"isLimitFree":false,"isBought":null,"isBorrowed":null,"isFree":false,"expireTime":null}
# Response:
{"took":7,"errors":true,"items":[{"index":{"_index":"book-indexer","_id":"452e6028-5665-40ad-9b8e-aed105015852","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":377,"_primary_term":1,"status":201},{"index":{"_index":"book-indexer","_id":"37cb21f9-fcaf-4a1c-ae9e-6887f7a6e972","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id '37cb21f9-fcaf-4a1c-ae9e-6887f7a6e972'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=strategy}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"c047d045-86e8-4ba6-9543-45fe059fa5fb","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id 'c047d045-86e8-4ba6-9543-45fe059fa5fb'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=stop-notice}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"3226a86a-473e-4a7a-8cce-7d51bd47a723","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id '3226a86a-473e-4a7a-8cce-7d51bd47a723'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"507ac681-1b80-482b-bdb8-9511e318e0b3","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id '507ac681-1b80-482b-bdb8-9511e318e0b3'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"55
96112c-d11c-4bca-aca8-cd5393f3cad1","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id '5596112c-d11c-4bca-aca8-cd5393f3cad1'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"dd697927-fa0a-4e07-ac85-610c70aae618","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id 'dd697927-fa0a-4e07-ac85-610c70aae618'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"df9d5b21-4223-43bb-9fe3-53ea0386463a","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id 'df9d5b21-4223-43bb-9fe3-53ea0386463a'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}},{"index":{"_index":"book-indexer","_id":"91267e17-87ad-47fe-980d-05870da88620","status":400,"error":{"type":"mapper_parsing_exception","reason":"failed to parse field [join] of type [text] in document with id '91267e17-87ad-47fe-980d-05870da88620'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=last-chapter}'","caused_by":{"type":"illegal_state_exception","reason":"Can't get text on a START_OBJECT at 1:9"}}}]}

How can one reproduce the bug?

My Code


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Lemon.Novel.Infrastructure;
using System.Threading.Tasks;
using OpenSearch.Net;
using OpenSearch.Client;

namespace Lemon.Novel.Domain.SDK
{

    public interface IOpenBookDocumentDemo
    {
        /// <summary>
        /// Id
        /// </summary>
        string Id { get; set; }

        /// <summary>
        /// Join
        /// </summary>
        JoinField Join { get; set; }
    }

    /// <summary>
    /// 
    /// </summary>
    [OpenSearchType(RelationName = "book-base")]
    public class OpenEsBookBaseDemo : IOpenBookDocumentDemo
    {
        public string Id { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public bool IsPay { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string[] Tags { get; set; }

        #region 

        /// <summary>
        /// 
        /// </summary>
        public string StrategyId { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public string PricingStrategyId { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public DateTime? LastChapterTime { get; set; }

        #endregion

        /// <summary>
        /// Join
        /// </summary>
        public JoinField Join { get; set; }

        public string SeriesId { get; set; }
        public int? SeriesOrder { get; set; }
        /// <summary>
        /// 系列与书的关联时间
        /// </summary>
        public DateTime? SeriesBookJoinTime { get; set; }

    }

    /// <summary>
    /// 
    /// </summary>
    [OpenSearchType(RelationName = "stop-notice")]
    public class OpenEsBookStopNoticeDemo : IOpenBookDocumentDemo
    {

        public string Id { get; set; }
        /// <summary>
        /// Join
        /// </summary>
        public JoinField Join { get; set; }
    }

    public class OpenSearchDemoClient : IFacade
    {

        private OpenSearchClient _elasticClient;

        private readonly Regex _esQueryRegex;

        private readonly string BookIndexer = "book-indexer";

        private readonly string ESHost = "localhost:9200";

        private readonly string ElasticUser = "";

        private readonly string ElasticPassword = "";

        public OpenSearchDemoClient()
        {
            _elasticClient = InitElasticClient(ESHost, "", "");
            _esQueryRegex = new Regex(@"(?:\w+\:\*(?<word>.*?)\*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        }

        private OpenSearchClient InitElasticClient(string elasticHost, string ElasticUser, string ElasticPassword)
        {
            var pool = new SingleNodeConnectionPool(new Uri(elasticHost));
            var connSettings = new OpenSearch.Client.ConnectionSettings(pool, OpenSearch.Client.JsonNetSerializer.JsonNetSerializer.Default);
            if (!string.IsNullOrEmpty(ElasticUser) && !string.IsNullOrEmpty(ElasticPassword))
            {
                connSettings.BasicAuthentication(ElasticUser, ElasticPassword);
            }
            connSettings.DisableDirectStreaming();
            return new OpenSearchClient(connSettings);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private async Task CreateIndexAsync()
        {
            var existsRep = await _elasticClient.Indices.ExistsAsync(BookIndexer);
            if (existsRep.ApiCall.HttpStatusCode == 200)
                return;
            var response = await _elasticClient.Indices.CreateAsync(
                BookIndexer, c => c
                .Index<OpenEsBookBaseDemo>()
                .Map<IOpenBookDocumentDemo>(m => m
                        .RoutingField(r => r.Required())
                        .AutoMap<OpenEsBookBaseDemo>()
                        .AutoMap<OpenEsBookStopNoticeDemo>()
                        .Properties(props => props
                            .Join(j => j
                                .Name(p => p.Join)
                                .Relations(r => r
                                    .Join<OpenEsBookBaseDemo, OpenEsBookStopNoticeDemo>()
                                )
                            )
                            // TODO:指定属性为keyword类型
                            .Keyword(s => s.Name(f => f.Id))
                            .Keyword(s => new KeywordPropertyDescriptor<OpenEsBookBaseDemo>().Name(f => f.StrategyId))
                            .Keyword(s => new KeywordPropertyDescriptor<OpenEsBookBaseDemo>().Name(f => f.PricingStrategyId))
                            .Keyword(s => new KeywordPropertyDescriptor<OpenEsBookBaseDemo>().Name(f => f.Tags))
                        )
                    )
            );
            if (!response.IsValid)
            {
                Console.WriteLine($"create indexer failed. debug info: {response.DebugInformation}");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="book"></param>
        /// <param name="children"></param>
        /// <returns></returns>
        public virtual async Task CreateBookDocumentAsync(OpenEsBookBaseDemo book, params IOpenBookDocumentDemo[] children)
        {
            await CreateIndexAsync();

            book.Join = JoinField.Root<OpenEsBookBaseDemo>();
            Func<BulkDescriptor, IBulkRequest> descriptor = s => s.Index<IOpenBookDocumentDemo>(i
                => i.Document(book)).Index(BookIndexer);
            if (children != null && children.Any(x => x != null))
            {
                children = children.Where(x => x != null).ToArray();
                foreach (var child in children)
                    child.Join = JoinField.Link(RelationName.Create(child.GetType()), book.Id);
                descriptor = s => s.Index<IOpenBookDocumentDemo>(i => i.Document(book)).IndexMany(children).Index(ElasticIndices.BookIndexer);
            }

            var response = await _elasticClient.BulkAsync(descriptor);
            if (!response.IsValid)

               Console.WriteLine($"create indexer failed. debug info: {response.DebugInformation}");
        }

    }
}

How I fix it? Thanks~

Xtansia commented 1 year ago

@liguobao Based on the errors like:

{
    "type": "mapper_parsing_exception",
    "reason": "failed to parse field [join] of type [text] in document with id '37cb21f9-fcaf-4a1c-ae9e-6887f7a6e972'. Preview of field's value: '{parent=452e6028-5665-40ad-9b8e-aed105015852, name=strategy}'",
    "caused_by": {
        "type": "illegal_state_exception",
        "reason": "Can't get text on a START_OBJECT at 1:9"
    }
}

It appears your index already exists but has an incorrect mapping, assuming this is not in production use yet have you tried removing the index and allowing it to be recreated by the code? As running your code locally for me works as expected.

If you go to http://{dashboards_url}:5601/app/dev_tools and run GET /book-indexer/_mapping you should get something like below:

{
  "book-indexer": {
    "mappings": {
      "_routing": {
        "required": true
      },
      "properties": {
        "id": {
          "type": "keyword"
        },
        "isPay": {
          "type": "boolean"
        },
        "join": {
          "type": "join",
          "eager_global_ordinals": true,
          "relations": {
            "book-base": "stop-notice"
          }
        },
        "lastChapterTime": {
          "type": "date"
        },
        "pricingStrategyId": {
          "type": "keyword"
        },
        "seriesBookJoinTime": {
          "type": "date"
        },
        "seriesId": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "seriesOrder": {
          "type": "integer"
        },
        "strategyId": {
          "type": "keyword"
        },
        "tags": {
          "type": "keyword"
        }
      }
    }
  }
}

Notice how the join property has "type": "join" with the relation information, however I expect in your case it will have "type": "text".

For reference the exact code I ran was:

using OpenSearch.Client;
using OpenSearch.Net;
using System.Text.RegularExpressions;

public static class Program
{
    public static async Task Main(string[] args)
    {
        var client = new OpenSearchDemoClient();

        await client.CreateBookDocumentAsync(new OpenEsBookBaseDemo
        {
            Id = Guid.NewGuid().ToString(),
            IsPay = false,
            LastChapterTime = DateTime.Parse("2019-06-13T16:56:40"),
            StrategyId = Guid.NewGuid().ToString(),
            Tags = new[] { "tag1", "tag2" }
        }, new OpenEsBookStopNoticeDemo
        {
            Id = Guid.NewGuid().ToString()
        });
    }
}

public interface IOpenBookDocumentDemo
{
    /// <summary>
    /// Id
    /// </summary>
    string Id { get; set; }

    /// <summary>
    /// Join
    /// </summary>
    JoinField Join { get; set; }
}

/// <summary>
/// 
/// </summary>
[OpenSearchType(RelationName = "book-base")]
public class OpenEsBookBaseDemo : IOpenBookDocumentDemo
{
    public string Id { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public bool IsPay { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public string[] Tags { get; set; }

    #region

    /// <summary>
    /// 
    /// </summary>
    public string StrategyId { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public string PricingStrategyId { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public DateTime? LastChapterTime { get; set; }

    #endregion

    /// <summary>
    /// Join
    /// </summary>
    public JoinField Join { get; set; }

    public string SeriesId { get; set; }
    public int? SeriesOrder { get; set; }

    /// <summary>
    /// 系列与书的关联时间
    /// </summary>
    public DateTime? SeriesBookJoinTime { get; set; }
}

/// <summary>
/// 
/// </summary>
[OpenSearchType(RelationName = "stop-notice")]
public class OpenEsBookStopNoticeDemo : IOpenBookDocumentDemo
{
    public string Id { get; set; }

    /// <summary>
    /// Join
    /// </summary>
    public JoinField Join { get; set; }
}

public class OpenSearchDemoClient
{
    private OpenSearchClient _elasticClient;

    private readonly Regex _esQueryRegex;

    private readonly string BookIndexer = "book-indexer";

    private readonly string ESHost = "https://localhost:9200";

    private readonly string ElasticUser = "admin";

    private readonly string ElasticPassword = "admin";

    public OpenSearchDemoClient()
    {
        _elasticClient = InitElasticClient(ESHost, ElasticUser, ElasticPassword);
        _esQueryRegex = new Regex(@"(?:\w+\:\*(?<word>.*?)\*)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    }

    private OpenSearchClient InitElasticClient(string elasticHost, string elasticUser, string elasticPassword)
    {
        var pool = new SingleNodeConnectionPool(new Uri(elasticHost));
        var connSettings =
            new OpenSearch.Client.ConnectionSettings(pool,
                OpenSearch.Client.JsonNetSerializer.JsonNetSerializer.Default);
        if (!string.IsNullOrEmpty(elasticUser) && !string.IsNullOrEmpty(elasticPassword))
        {
            connSettings.BasicAuthentication(elasticUser, elasticPassword);
        }

        connSettings.ServerCertificateValidationCallback(CertificateValidations.AllowAll);
        connSettings.DisableDirectStreaming();
        return new OpenSearchClient(connSettings);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    private async Task CreateIndexAsync()
    {
        var existsRep = await _elasticClient.Indices.ExistsAsync(BookIndexer);
        if (existsRep.ApiCall.HttpStatusCode == 200)
            return;
        var response = await _elasticClient.Indices.CreateAsync(
            BookIndexer, c => c
                .Map<IOpenBookDocumentDemo>(m => m
                    .RoutingField(r => r.Required())
                    .AutoMap<OpenEsBookBaseDemo>()
                    .AutoMap<OpenEsBookStopNoticeDemo>()
                    .Properties(props => props
                        .Join(j => j
                            .Name(p => p.Join)
                            .Relations(r => r
                                .Join<OpenEsBookBaseDemo, OpenEsBookStopNoticeDemo>()
                            )
                        )
                        .Keyword(s => s.Name(f => f.Id))

                    )
                    .Properties<OpenEsBookBaseDemo>(props => props
                        .Keyword(s => s.Name(f => f.StrategyId))
                        .Keyword(
                            s => s.Name(f => f.PricingStrategyId))
                        .Keyword(s => s.Name(f => f.Tags))
                    )
                )
        );
        if (!response.IsValid)
        {
            Console.WriteLine($"create indexer failed. debug info: {response.DebugInformation}");
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="book"></param>
    /// <param name="children"></param>
    /// <returns></returns>
    public virtual async Task CreateBookDocumentAsync(OpenEsBookBaseDemo book, params IOpenBookDocumentDemo[] children)
    {
        await CreateIndexAsync();

        book.Join = JoinField.Root<OpenEsBookBaseDemo>();
        Func<BulkDescriptor, IBulkRequest> descriptor = s => s.Index<IOpenBookDocumentDemo>(i
            => i.Document(book)).Index(BookIndexer);
        if (children != null && children.Any(x => x != null))
        {
            children = children.Where(x => x != null).ToArray();
            foreach (var child in children)
                child.Join = JoinField.Link(RelationName.Create(child.GetType()), book.Id);
            descriptor = s =>
                s.Index<IOpenBookDocumentDemo>(i => i.Document(book)).IndexMany(children)
                    .Index(BookIndexer);
        }

        var response = await _elasticClient.BulkAsync(descriptor);
        if (!response.IsValid)

            Console.WriteLine($"create indexer failed. debug info: {response.DebugInformation}");
    }
}