Back to "Πλήρης Αναζήτηση κειμένου (Pt ΜSK1 ΜSK2 OpenSearch με ASP ΜСК3NET Core ΜΣΚ4"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET OpenSearch

Πλήρης Αναζήτηση κειμένου (Pt ΜSK1 ΜSK2 OpenSearch με ASP ΜСК3NET Core ΜΣΚ4

Saturday, 24 August 2024

Εισαγωγή

Στα προηγούμενα μέρη αυτής της σειράς εισήγαγαμε την έννοια της πλήρους αναζήτησης κειμένου και πώς μπορεί να χρησιμοποιηθεί για την αναζήτηση κειμένων μέσα σε μια βάση δεδομένων.Σε αυτό το μέρος θα παρουσιάσουμε τον τρόπο χρήσης του OpenSearch με ASP.NET CoreM SK2

Προηγούμενο άρθροΕπίσημα

Σε αυτό το τμήμα θα περιγράψουμε πώς να ξεκινήσετε τη χρήση της νέας λαμπερή παραδείγματος OpenSearch με ASP.NET Core.

Ρυθμίσεις

Μόλις έχουμε την ένδειξη OpenSearch και τρέχουμε μπορούμε να αρχίσουμε να αλληλεπιδράμε μαζί της.Θα χρησιμοποιήσουμε το OpenSearch Πελάτης Για .NETΜSK1 Πρώτα καθορίζουμε τον πελάτη στην επέκταση εγκατάστασης μας

    var openSearchConfig = services.ConfigurePOCO<OpenSearchConfig>(configuration.GetSection(OpenSearchConfig.Section));
        var config = new ConnectionSettings(new Uri(openSearchConfig.Endpoint))
            .EnableHttpCompression()
            .EnableDebugMode()
            .ServerCertificateValidationCallback((sender, certificate, chain, errors) => true)
            .BasicAuthentication(openSearchConfig.Username, openSearchConfig.Password);
        services.AddSingleton<OpenSearchClient>(c => new OpenSearchClient(config));

Αυτό συγκεντρώνει τον πελάτη με το τελικό σημείο και τα πιστοποιητικά.Μπορούμε επίσης να ενεργοποιήσουμε τη λειτουργία αποσύνδεσης έτσι ώστε να μπορούμε να δούμε τι' περνάει σεM SK2Περισσότερα καθώς γνωρίζουμε ότι η ' δεν χρησιμοποιεί REAL SSL πιστοποιήσεις απενεργοποιούμε την επικύρωση πιστοληπτικής Η (ΜSK5 κάνει αυτό στην παραγωγή

Εισαγωγή δεδομένων

Η κεντρική έννοια του OpenSearch είναι ο δείκτης.Να σκεφτείτε έναν δείκτη όπως ένας πίνακας βάσης δεδομένωνΜSK1 αυτό' όπου όλα τα δεδομένα σας αποθηκεύονται

Για να το κάνουμε αυτό θα χρησιμοποιήσουμε την OpenSearch Πελάτης για .NET.Μπορείτε να το εγκαταστήσετε μέσω του NuGetM SK2

You'll notice there'll two there M SK2OpensearchMK3Net και Opensearch<.Client.Το πρώτο είναι το χαμηλό επίπεδο στοιχείων όπως η διαχείριση σύνδεσηςΜSK6 το δεύτερο είναι τα υψηλά επίπεδα στοιχειών όπως ο δείκτης και η αναζήτησηMSKA7

Τώρα που το έχουμε εγκαταστήσει, μπορούμε να αρχίσουμε να εξετάζουμε τα δεδομένα indexing.

Δημιουργία ενός δείκτη είναι ημι-straightforward. Απλά προσδιορίζετε τι πρέπει να φαίνεται ο δείκτης σας και στη συνέχεια δημιουργήστε τοM SK2 Στο κώδικα παρακάτω μπορείτε να δείτε εμάς 'map' Index Model μας ΜSK2 απλουστευμένη έκδοση του blogM SK3 database model Για κάθε πεδίο αυτού του μοντέλου, τότε καθορίζουμε ποιο είδος είναι (text, dateM SK2 keyword κλπMK3 και τι αναλυτής να χρησιμοποιήσετε

Ο τύπος είναι σημαντικός καθώς καθορίζει πώς αποθηκεύονται τα δεδομένα και πώς μπορούν να αναζητηθούν. Για παράδειγμα, το , ένα 'ΜSK3 πεδίο αναλύεται και κωδικοποιείταιΤο , ένας ΜSK5 λέξη-κλειδί Το ' πεδία δεν είναι . Έτσι μπορείτε να περιμένετε ότι η ' αναζητάει για ένα κλειδιά λέξης ακριβώς όπως είναι αποθηκευμένοΗ , αλλά ένα κείμενο πεδίου μπορείτε να ψάξετε για μέρη του κειμένου

Επίσης εδώ οι κατηγορίες είναι στην πραγματικότητα μια γραμμή[] αλλά ο τύπος λέξεων-κλειδιών καταλαβαίνει πώς να τα χειριστεί σωστάΜSK1

   public async Task CreateIndex(string language)
    {
        var languageName = language.ConvertCodeToLanguageName();
        var indexName = GetBlogIndexName(language);

      var response =  await client.Indices.CreateAsync(indexName, c => c
            .Settings(s => s
                .NumberOfShards(1)
                .NumberOfReplicas(1)
            )
            .Map<BlogIndexModel>(m => m
                .Properties(p => p
                    .Text(t => t
                        .Name(n => n.Title)
                        .Analyzer(languageName)
                    )
                    .Text(t => t
                        .Name(n => n.Content)
                        .Analyzer(languageName)
                    )
                    .Text(t => t
                        .Name(n => n.Language)
                    )
                    .Date(t => t
                        .Name(n => n.LastUpdated)
                    )
                    .Date(t => t
                        .Name(n => n.Published)
                    )
                    .Date(t => t
                        .Name(n => n.LastUpdated)
                    )
                    .Keyword(t => t
                        .Name(n => n.Id)
                    )
                    .Keyword(t=>t
                        .Name(n=>n.Slug)
                    )
                    .Keyword(t=>t
                        .Name(n=>n.Hash)
                    )
                    .Keyword(t => t
                        .Name(n => n.Categories)
                    )
                )
            )
        );
        
        if (!response.IsValid)
        {
           logger.LogError("Failed to create index {IndexName}: {Error}", indexName, response.DebugInformation);
        }
    }

Προσθήκη στοιχείων στον δείκτη

Μόλις έχουμε τον δείκτη μας εγκατεστημένο για να προσθέσουμε στοιχεία σε αυτό θα πρέπει να προσθέσεις στοιχεία σε αυτόν τον δείκτη. Εδώ καθώς χρειαζόμαστε' προσθέτοντας ένα BUNCH χρησιμοποιούμε μια μέθοδο μαζικής εισαγωγής.

Μπορείτε να δείτε ότι καλούμε αρχικά σε μια μέθοδο που ονομάζεταιGetExistingPosts που επιστρέφει όλες τις δημοσιεύσεις που είναι ήδη στον δείκτη. Εμείς στη συνέχεια συγκεντρώσουμε τα δημοσιεύματα με γλώσσα και φιλτράρετε έξω το 'ukΜSK2 γλώσσα ΜSK3as δίνουμε 't θέλουν να index that δεδομένου ότι χρειάζεται ένα πρόσθετο plugin δεν έχουμε ΜΚ5t έχουν ακόμα ΜΣΚ6 Στη συνέχεια φίλτουμε έξω οποιαδήποτε δημοσιεύμα που βρίσκεται ήδη στο δείκτη Χρησιμοποιούμε το hash και το ID για να προσδιορίσουμε εάν ένα post είναι ήδη στον δείκτη.

    public async Task AddPostsToIndex(IEnumerable<BlogIndexModel> posts)
    {
        var existingPosts = await GetExistingPosts();
        var langPosts = posts.GroupBy(p => p.Language);
        langPosts=langPosts.Where(p => p.Key!="uk");
        langPosts = langPosts.Where(p =>
            p.Any(post => !existingPosts.Any(existing => existing.Id == post.Id && existing.Hash == post.Hash)));
        
        foreach (var blogIndexModels in langPosts)
        {
            
            var language = blogIndexModels.Key;
            var indexName = GetBlogIndexName(language);
            if(!await IndexExists(language))
            {
                await CreateIndex(language);
            }
            
            var bulkRequest = new BulkRequest(indexName)
            {
                Operations = new BulkOperationsCollection<IBulkOperation>(blogIndexModels.ToList()
                    .Select(p => new BulkIndexOperation<BlogIndexModel>(p))
                    .ToList()),
                Refresh = Refresh.True,
                ErrorTrace = true,
                RequestConfiguration = new RequestConfiguration
                {
                    MaxRetries = 3
                }
            };

            var bulkResponse = await client.BulkAsync(bulkRequest);
            if (!bulkResponse.IsValid)
            {
                logger.LogError("Failed to add posts to index {IndexName}: {Error}", indexName, bulkResponse.DebugInformation);
            }
            
        }
    }

Μόλις βρήκαμε've φιλτραρισμένα τα υπάρχοντα posts και το λείπουν αναλυτή μας δημιουργούμε ένα νέο Index ( βασισμένο στο όνομα, στην περίπτωση μου ΜSK3mostlylucidM SK4blogMK5") και στη συνέχεια δημιουργήστε μια αίτηση μάζαςΜSK1 Αυτό το αίτημα μάζα είναι μια συλλογή εργασιών που πρέπει να εκτελούνται στον δείκτη. Αυτό είναι πιο αποτελεσματικό από το να προσθέσετε κάθε στοιχείο ένα με ένα.

Σας αρέσει το ' αναμένεται να δείτε αυτό στο BulkRequest Εμείς θέτουμε το Refresh Ιδιοκτησία για true. Αυτό σημαίνει ότι μετά την πλήρη εισαγωγή, ο δείκτης ανανεώνεταιΜSK1 Αυτό δεν είναι σίγουρα το ' αναφέρει ΠΡΑΓΜΑΤΙΚΑ απαραίτητο αλλά αυτό είναι σίγουρο ότι το ΜSK3 αναφέρει χρήσιμη για την αποσύνδεση

Αναζητώντας τον δείκτη

Ένας καλός τρόπος να δοκιμάσετε για να δείτε τι το ' αναφέρει πραγματικά δημιουργήθηκε εδώ είναι να πάτε στα Dev Tools στο OpenSearch Dashboards και να εκτελέσετε μια έρευνα αναζήτησης για το . αναφέρουν

GET /mostlylucid-blog-*
{}

Αυτή η ερώτηση θα μας επιστρέψει όλους τους δείκτες που ταιριάζουν με το πρότυπο mostlylucid-blog-*. ΜSK1όσο όλοι οι δείκτες μας μέχρι στιγμής ΜSK2

{
  "mostlylucid-blog-ar": {
    "aliases": {},
    "mappings": {
      "properties": {
        "categories": {
          "type": "keyword"
        },
        "content": {
          "type": "text",
          "analyzer": "arabic"
        },
        "hash": {
          "type": "keyword"
        },
        "id": {
          "type": "keyword"
        },
        "language": {
          "type": "text"
        },
        "lastUpdated": {
          "type": "date"
        },
        "published": {
          "type": "date"
        },
        "slug": {
          "type": "keyword"
        },
        "title": {
          "type": "text",
          "analyzer": "arabic"
        }
      }
    },
    "settings": {
      "index": {
        "replication": {
          "type": "DOCUMENT"
..MANY MORE

Dev Tools στο OpenSearch Dashboards είναι ένας πολύ καλός τρόπος για να δοκιμάσετε τις ερωτήσεις σας πριν τα βάλετε στον κώδικα σας.

Dev Εργαλεία

Αναζητώντας τον δείκτη

Τώρα μπορούμε να ξεκινήσουμε την αναζήτηση του δείκτη.Μπορούμε να χρησιμοποιήσουμε το Search Μέθοδος για τον πελάτη να το κάνει αυτό. Αυτό είναι όπου η πραγματική δύναμη του OpenSearch έρχεται στο. Έχει κυριολεκτικά Δέκα διαφορετικά είδη ερωτήσεων Μπορείτε να το χρησιμοποιήσετε για την αναζήτηση των δεδομένων σας.Όλα από μια απλή αναζήτηση λέξεων-κλειδιών σε ένα σύνθετο 'ΜSK2Αναζήτηση

    public async Task<List<BlogIndexModel>> GetSearchResults(string language, string query, int page = 1, int pageSize = 10)
    {
        var indexName = GetBlogIndexName(language);
        var searchResponse = await client.SearchAsync<BlogIndexModel>(s => s
                .Index(indexName)  // Match index pattern
                .Query(q => q
                    .Bool(b => b
                        .Must(m => m
                            .MultiMatch(mm => mm
                                .Query(query)
                                .Fields(f => f
                                    .Field(p => p.Title, boost: 2.0) 
                                    .Field(p => p.Categories, boost: 1.5) 
                                    .Field(p => p.Content)
                                )
                                .Type(TextQueryType.BestFields)
                                .Fuzziness(Fuzziness.Auto)
                            )
                        )
                    )
                )
                .Skip((page -1) * pageSize)  // Skip the first n results (adjust as needed)
                .Size(pageSize)  // Limit the number of results (adjust as needed)
        );

        if(!searchResponse.IsValid)
        {
            logger.LogError("Failed to search index {IndexName}: {Error}", indexName, searchResponse.DebugInformation);
            return new List<BlogIndexModel>();
        }
        return searchResponse.Documents.ToList();
    }

Περιγραφή Query

Αυτή η μέθοδος, GetSearchResults, επιχειρήσεις έχει σχεδιαστεί για να αναζητήσει ένα συγκεκριμένο δείκτη OpenSearch για την ανάκτηση ιστολογικών δημοσιεύσεωνΜSK1 επιχειρήσεις Χρειάζονται τρεις παραμέτρους language, query, αναφορές και παραμέτρους σελίδας page και pageSize. ΕδώΗ ' αναφέρει τι κάνει η : αναφέρει

  1. Δείκτης επιλογής:

    • Αποκτά το όνομα του δείκτη χρησιμοποιώντας την GetBlogIndexName μέθοδος που βασίζεται στη γλώσσα που παρέχεται. Ο δείκτης επιλέγεται δυναμικά σύμφωνα με τη γλώσσα.
  2. Αναζήτηση Query:

    • Η ερώτηση χρησιμοποιεί ένα Bool Ερωτηθείτε με A Must ρήτρα για να διασφαλιστεί ότι τα αποτελέσματα πληρούν ορισμένα κριτήρια.
    • Στο εσωτερικό της Must ΠΡΟΣΟΧΗ ΣΤΗΝ ΚΥΚΛΗΣΙΑ Α MultiMatch Το ερώτημα χρησιμοποιείται για την αναζήτηση σε πολλά πεδία (Title, Categories, επιχειρήσεις και Content).
      • Ενίσχυση: Το Title Το πεδίο έχει ενισχυθεί 2.0, το κάνει πιο σημαντικό στην αναζήτησηΜSK1 και Categories Έχει μια αύξηση της 1.5. Αυτό σημαίνει ότι τα έγγραφα όπου η αναζήτηση εμφανίζεται στον τίτλο ή τις κατηγορίες θα κατατάσσονται υψηλότεραΜSK1
      • Τύπος Query: Χρησιμοποιεί BestFields, που προσπαθεί να βρει το καλύτερο πεδίο αντιστοίχισης για την ερώτησηΜSK1
      • Φοβαρία: Το Fuzziness.Auto παράμετρος επιτρέπει για κοντινούς αγώνες ( αναφέρει ΜSK1 αναφέρει ., αναφέρει χειρισμό μικρών τύπων ΜSK3 αναφέρει
  3. Παιχνιδια:

    • Η Skip Η μέθοδος σκάβει το πρώτο n Τα αποτελέσματα ανάλογα με τον αριθμό σελίδων, υπολογίζονται ως (page - 1) * pageSize. Αυτό βοηθά στην πλοήγηση μέσω σελινών αποτελεσμάτωνΜSK1
    • Η Size Η μέθοδος περιορίζει τον αριθμό των εγγράφων που επιστρέφονται στο καθορισμένο pageSize.
  4. Λάθος επεξεργασίας:

    • Εάν το ερώτημα αποτύχει, ένα σφάλμα είναι συνδεδεμένο και μια κενή λίστα επιστρέφεταιΜSK1
  5. Αποτέλεσμα:

    • Η μέθοδος επιστρέφει μια λίστα BlogIndexModel έγγραφα που ταιριάζουν με τα κριτήρια αναζήτησης.

Έτσι μπορείτε να δείτε ότι μπορούμε να είμαστε εξαιρετικά ευέλικτοι σχετικά με τον τρόπο που αναζητούμε τα δεδομένα μας.Μπορούμε να αναζητήσουμε συγκεκριμένα πεδία,ΜΠΟΡΟΥΜΕ να ενισχύσουμε ορισμένες πεδίεςMK2Μπόρεσε ακόμη και να αναζήτηση σε πολλαπλούς δείκτεςMk3

Ένα μεγάλο πλεονέκτημα είναι η ευκολία qith που μπορούμε να υποστηρίξουμε πολλές γλώσσες.Έχουμε διαφορετικό δείκτη για κάθε γλώσσα και επιτρέπει την αναζήτηση μέσα σε αυτόν τον δείκτηΜSK1 Αυτό σημαίνει ότι μπορούμε да χρησιμοποιήσουμε το σωστό αναλυτή για κάθε γλωσσάκι και να λάβουμε τα καλύτερα αποτελέσματα.

Η νέα API αναζήτησης

Σε αντίθεση με το Search API που είδαμε στα προηγούμενα μέρη αυτής της σειράς, μπορούμε να απλοποιήσουμε σημαντικά τη διαδικασία αναζήτησης χρησιμοποιώντας OpenSearch.Μπορούμε απλά να ρίξουμε κείμενο σε αυτή την έρευνα και να πάρετε καλά αποτελέσματα πίσωM SK2

   [HttpGet]
    [Route("osearch/{query}")]
   [ValidateAntiForgeryToken]
    public async Task<JsonHttpResult<List<SearchResults>>> OpenSearch(string query, string language = MarkdownBaseService.EnglishLanguage)
    {
        var results = await indexService.GetSearchResults(language, query);
        
        var host = Request.Host.Value;
        var output = results.Select(x => new SearchResults(x.Title.Trim(), x.Slug, @Url.ActionLink("Show", "Blog", new{ x.Slug}, protocol:"https", host:host) )).ToList();
        return TypedResults.Json(output);
    }

Όπως μπορείτε να δείτε έχουμε όλα τα δεδομένα που χρειαζόμαστε στον δείκτη για την επιστροφή των αποτελεσμάτων.Μπορούμε στη συνέχεια να χρησιμοποιήσουμε αυτό για τη δημιουργία ενός URL στο blog post.Αυτό παίρνει το φορτίο από τη βάση δεδομένων μας και καθιστά τη διαδικασία αναζήτησης πολύ πιο γρήγορη

Στο συμπέρασμα

Σε αυτό το άρθρο, είδαμε πώς να γράψουμε έναν πελάτη C# για να αλληλεπιδράσουμε με την περίπτωση OpenSearch μας.

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.