[SpringCloud] Einführung in den Microservice Technology Stack 8 – Praktische Hinweise zum Dark Horse Tourism Microservice Project

Dark Horse Reiseetui


Paging-Abfrage

Die Front-End-Seite und die entsprechende Anforderungsschnittstelle wurden eingerichtet und wir müssen nur noch den entsprechenden Back-End-Inhalt hinzufügen.

Legen Sie zunächst die Entitätsklasse fest, die die Anfrage empfängt

@Data
public class RequestParams {
    
    
    private String key;
    private Integer page;
    private Integer size;
    private String sortBy;
}

Als nächstes wird die Antwortklasse an das Frontend zurückgegeben (der Feldname muss mit dem Frontend übereinstimmen, sonst wird der Inhalt, den Sie an das Frontend übergeben, nicht erkannt).

@Data
public class PageResult {
    
    
    private Long total;
    private List<HotelDoc> hotels;

    public PageResult() {
    
    
    }

    public PageResult(Long total, List<HotelDoc> hotels) {
    
    
        this.total = total;
        this.hotels = hotels;
    }
}

Neuen Abfrage-Controller hinzufügen

@RestController
@RequestMapping("/hotel")
public class HotelController {
    
    
    @Autowired
    private IHotelService hotelService;

    @PostMapping("/list")
    PageResult search(@RequestBody RequestParams params) {
    
    
        return hotelService.search(params);
    }
}

Implementieren Sie bestimmte Vorgänge im entsprechenden Dienst

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
    
    
    @Autowired
    private RestHighLevelClient client;

    @Override
    public PageResult search(RequestParams params) {
    
    
        try {
    
    
            SearchRequest request = new SearchRequest("hotel");

            // 判断请求是否包含指定params,以此来选择查询方式
            String key = params.getKey();
            if (key == null || "".equals(key)) {
    
    
                request.source().query(QueryBuilders.matchAllQuery());
            } else {
    
    
                request.source().query(QueryBuilders.matchQuery("all", key));
            }

            // 分页
            Integer page = params.getPage(), size = params.getSize();
            request.source().from((page - 1) * size).size(size);

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);

            return logResp(response);
        } catch (IOException e) {
    
    
            throw new RuntimeException();
        }
    }

    // 此方法将包装从es中查询到的所有文档到对象PageResult内,然后作为响应返回前端
    private PageResult logResp(SearchResponse response) {
    
    
        SearchHits searchHits = response.getHits();
        SearchHit[] hits = searchHits.getHits();
        System.out.println(searchHits.getTotalHits().value + "条数据");

        List<HotelDoc> hotelDocs = new ArrayList<>();
        for (SearchHit hit : hits) {
    
    
            String source = hit.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(source, HotelDoc.class);
            hotelDocs.add(hotelDoc);
        }

        return new PageResult(searchHits.getTotalHits().value, hotelDocs);
    }
}

automatische Vervollständigung

Wenn wir nach Dingen suchen, stellen wir oft fest, dass jedes Mal, wenn wir ein Wort eingeben, viele verwandte Inhalte damit verknüpft sind. Wir verwenden den Pinyin-Wortsegmentierer, um Wortsegmentierungsoperationen durchzuführen und diese Funktion zu erreichen.

Abhängigkeiten installieren

Der Tokenizer von es besteht aus drei Teilen:

  • character filtersEinfache Verarbeitung von Text, z. B. Entfernen von Ersatzzeichen
  • tokenizerZerlegen Sie den Text nach bestimmten Regeln in Begriffe
  • tokenizer filterVerfeinern Sie die Tokenizer-Ergebnisse weiter, z. B. Groß-/Kleinschreibung und Synonymverarbeitung

Daunter sind die IK-Tokenizer-Prozesse tokenizer und die Pinyin-Tokenizer-Prozesse tokenizer filter

Laden Sie den Pinyin-Wortsegmentierer herunter. Die Installationsschritte entfallen:Adresse herunterladen


Benutzerdefinierter Tokenizer

Konfigurieren Sie einen benutzerdefinierten Tokenizer. Der Tokenizer heißt my_analyzer

PUT /test
{
    
    
  "settings": {
    
    
    "analysis": {
    
    
      "analyzer": {
    
    
        "my_analyzer": {
    
    
          "tokenizer": "ik_max_word",
          "filter": "py"
        }
      },
      "filter": {
    
    
        "py": {
    
    
          "type": "pinyin",
          "keep_full_pinyin": false,
          "keep_joined_full_pinyin": true,
          "keep_original": true,
          "limit_first_letter_length": 16,
          "remove_duplicated_term": true,
          "none_chinese_pinyin_tokenize": false
        }
      }
    }
  },
  "mappings": {
    
    
    "properties": {
    
    
      "name":{
    
    
        "type": "text",
        "analyzer": "my_analyzer"
      }
    }
  }
}

Führen Sie dann einen Test durch, um zu sehen, wie gut unser Tokenizer funktioniert

POST /test/_analyze
{
    
    
  "text": ["如家酒店真不戳"],
  "analyzer": "my_analyzer"
}

Abschlussvorschlag

Beim Erstellen eines invertierten Index: Verwenden Sie einen benutzerdefinierten Wortsegmentierer, um chinesische Wörter und Pinyin zu segmentieren
Bei der Suche von Benutzern: Verwenden Sie direkt den ik_smart-Wortsegmentierer

Merkmale des Abschlussvorschlags:

  1. Completion Suggester ist eine erweiterte Funktion zur automatischen Vervollständigung und Vorschlagsfunktion. Es kann passende Vorschläge basierend auf einigen vom Benutzer eingegebenen Begriffen bereitstellen.
  2. Der Feldtyp „Vervollständigungsvorschlag“ verwendet eine bestimmte Datenstruktur, um vorgeschlagenen Text zu speichern. Es verwendet invertierte Indizes und endliche Automaten (FSA), um effiziente Vorschlagsabfragen bereitzustellen.
  3. Die Ergebnisse einer Completion Suggester-Abfrage enthalten einen Vorschlagsabschnitt mit vorgeschlagenen Ergebnissen, die mit der Abfrage übereinstimmen. Jedes Vorschlagsergebnis enthält ein Optionsarray mit dem Vorschlagstext und anderen relevanten Informationen.

Hier ist ein Beispiel: Erstellen Sie einen Indexmyindex, fügen Sie drei zufällige Daten ein und verwenden Sie Completion Suggester, um die Felder zu koppelntitle Mache eine Anfrage.

  1. Index erstellenmyindex und Feldzuordnung definieren: Das Feld von
    title mit dem Typ completion dient der Vorschlagsabfrage gebraucht!
PUT /myindex
{
    
    
  "mappings": {
    
    
    "properties": {
    
    
      "title": {
    
    
        "type": "completion"
      }
    }
  }
}
  1. Fügen Sie drei zufällige Daten in den Index einmyindex:
POST /myindex/_doc/1
{
    
    
  "title": {
    
    
    "input": ["Apple", "iPhone"]
  }
}

POST /myindex/_doc/2
{
    
    
  "title": {
    
    
    "input": ["Samsung", "Galaxy"]
  }
}

POST /myindex/_doc/3
{
    
    
  "title": {
    
    
    "input": ["Google", "Pixel"]
  }
}

Die obige Operation fügt drei Dokumente in den Index einmyindex, jedes Dokument enthält ein title Feld, wobeiinputArray Definiert vorgeschlagenen Text.

  1. Abfrage mit Completion Suggester:
GET /myindex/_search
{
    
    
  "suggest": {
    
    
    "suggestion": {
    
      // Completion Suggester的名称,可以自定义
      "prefix": "i",  // 指定以字母"i"开头的前缀
      "completion": {
    
    
        "field": "title",  // 指定要执行建议查询的字段为"title"
        "size": 10  // 指定返回的建议结果数量,这里设置为10
      }
    }
  }
}

Die obige Abfrage verwendet Completion Suggester, um im Feld nach vorgeschlagenem Text zu suchen, der mit den Buchstaben „i“ beginnttitle

Nach dem Ausführen der Abfrage erhalten Sie vorgeschlagene Ergebnisse, die mit der Abfrage übereinstimmen, ähnlich der folgenden Beispielantwort:

{
    
    
	"suggest": {
    
    
		"suggestion": [
			{
    
    
				"text": "i",
				"offset": 0,
				"length": 1,
				"options": [
					{
    
    
						"text": "iPhone",
						"score": 1.0
					}
				]
			}
		]
	}
}

Daten sammeln


Aggregierte Klassifizierung

Die Aggregation kann in drei Kategorien unterteilt werden

Fügen Sie hier eine Bildbeschreibung ein


Bucket-Aggregation

Verwenden Sie das Feld aggs für die Aggregationsabfrage. Im Bucket der Aggregationsabfrage gibt es standardmäßig ein Feld“_count”, das zur Darstellung derselben gefundenen Datenmenge verwendet wird

// GET请求示例,执行聚合查询
GET /hotel/_search
{
    
    
	"size": 0, // 设置搜索结果的大小为0,只返回聚合结果
	"aggs": {
    
    
		"brandAgg": {
    
    
			// 聚合名称为brandAgg
			"terms": {
    
    
				"field": "brand", // 根据brand字段进行分组
				"order": {
    
    
					"_count": "asc" // 按照聚合桶中文档数量的升序排序
				},
				"size": 20 // 返回前20个分组
			}
		}
	}
}

Fügen Sie auf ähnliche Weise ein zusätzliches Abfragefeld hinzu, das es uns ermöglicht, den abzufragenden Index auf einen bestimmten Bereich zu beschränken
Dadurch kann das Problem der Speichernutzung bei der Abfrage aller Indizes vermieden werden

GET /hotel/_search
{
    
    
  // 只对价格200及以下的酒店进行统计
  "query": {
    
    
    "range": {
    
    
      "price": {
    
    
        "lte": 200
      }
    }
  },
  "size": 0,
  "aggs": {
    
    
    "brandAgg": {
    
    
      "terms": {
    
    
        "field": "brand",
        "order": {
    
    
          "_count": "asc"
        },
        "size": 20
      }
    }
  }
}

Metrix-Aggregation

Schreiben Sie eine weitere Aggregation in die Aggregation, die einer Unteraggregation entspricht. Die Unteraggregation wird auf die gleiche Weise wie eine gewöhnliche Aggregation definiert.

stats wird verwendet, um grundlegende Daten wie min、max、avg der angegebenen Felder zu zählen

GET /hotel/_search
{
    
    
  "size": 0,
  "aggs": {
    
    
    "brandAgg": {
    
    
      "terms": {
    
    
        "field": "brand",
        "size": 20
      },
      "aggs": {
    
    
        "scoreAgg": {
    
    
          "stats": {
    
    
            "field": "score"
          }
        }
      }
    }
  }
}

RestClient implementiert die Aggregation

@Test
void testAgg() throws IOException {
    
    
    // 这一块执行聚合查询
    SearchRequest request = new SearchRequest("hotel");
    request.source().size(0);
    request.source().aggregation(AggregationBuilders
            .terms("brandAgg")
            .field("brand")
            .size(10)
    );

    // 这一段取出聚合查询的结果
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    Aggregations aggregations = response.getAggregations();
    Terms brandAgg = aggregations.get("brandAgg");
    List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();
    for (Terms.Bucket bucket : buckets) {
    
    
        String keyAsString = bucket.getKeyAsString();
        System.out.println(keyAsString);
    }
}

Abfrageergebnisse vorschlagen

Schreiben Sie den Vorschlag für die Abfragemethode. Die folgende Abbildung entspricht der Abfragemethode und ihrer Java-Schreibmethode.

Fügen Sie hier eine Bildbeschreibung ein

Nachdem die Abfrage abgeschlossen ist, ist es selbstverständlich, den zurückgegebenen JSON zu analysieren

Fügen Sie hier eine Bildbeschreibung ein


Die Front-End-Implementierung des automatischen Vervollständigungseffektprozesses:

  1. Erkennen Sie Änderungen in der Benutzereingabe im Suchfeld und senden Sie sie mithilfe einer Get-Anfrage. Params ist der Inhalt des aktuellen Eingabefelds.
  2. Das Backend empfängt die Get-Anfrage, analysiert die Requestparams und ruft den Inhalt des Eingabefelds ab.
  3. Verwenden Sie den Vorschlag, um den Inhalt an es zu senden. Nachdem es das Ergebnis analysiert und zurückgegeben hat, wird es vom Backend analysiert.
  4. Die aus der Abfrage erhaltene Liste wird an das Frontend zurückgegeben, fertig!

Datensynchronisation


Synchronisationsstrategie

Nach dem Ändern von MySQL bleibt der ES-Inhalt unverändert. Sie müssen die entsprechende Synchronisationsstrategie verwenden, damit ES die Daten synchron aktualisiert.

Synchrone Aufrufstrategie: Der Hotelverwaltungsdienst ändert zuerst MySQL und ruft dann die Schnittstelle auf, damit der Hotelsuchdienst es ändern kann (einfach und grob, hoher Kopplungsgrad).

Asynchrone Benachrichtigungsstrategie: Nachdem der Hotelverwaltungsdienst MySQL geändert hat, sendet er die Anforderung zur Änderung von es an mq, und der Hotelsuchdienst verarbeitet die Änderungsanforderungen nacheinander in mq (geringe Kopplung, einfach zu implementieren, abhängig von mq).

Überwachung der Binlog-Strategie: Der Prozess des Sendens von Anfragen durch den Hotelverwaltungsdienst entfällt. Stattdessen überwacht mq MySQL-Änderungen direkt und benachrichtigt den Hotelsuchdienst entsprechend, um Änderungen vorzunehmen (völlig entkoppelt, aber das Einschalten von Binlog erhöht die Belastung der Datenbank).
Fügen Sie hier eine Bildbeschreibung ein


mq-Synchronisierung

Fügen Sie hier eine Bildbeschreibung ein


Es richtet einen Cluster ein

Fügen Sie hier eine Bildbeschreibung ein

Die ES-Master-Slave-Struktur leidet häufig unter dem sogenannten Split-Brain-Problem: Knoten im Cluster können aufgrund von Netzwerkpartitionen oder anderen Fehlern nicht miteinander kommunizieren, was zur Bildung mehrerer unabhängiger Subcluster im Cluster führt . Dies kann zu Dateninkonsistenzen und Betriebskonflikten führen (menschlich ausgedrückt werden mehrere Master generiert).

Konfigurationsdateilösung: In der Elasticsearch-Konfigurationsdatei können Sie den Parameter discovery.zen.minimum_master_nodes festlegen, um die Mindestanzahl der im Cluster erforderlichen Masterknoten anzugeben. Dies kann dazu beitragen, die automatische Wahl mehrerer Master in einem Split-Brain-Szenario zu verhindern. Es wird empfohlen, diesen Parameter auf die Hälfte der Anzahl der Masterknoten im Cluster plus eins festzulegen
(es7 und höhere Versionen haben dieses Attribut automatisch festgelegt, sodass im Allgemeinen kein Split-Brain-Problem vorliegt)< /span>


Fügen Sie hier eine Bildbeschreibung ein

es Sharding-Prinzip

es verwendet den Hash-Algorithmus, um zu bestimmen, in welchem ​​Shard das aktuelle Dokument gespeichert werden soll.
Da der Hash-Algorithmus mit der Anzahl der es-Shards zusammenhängt, sobald die Indexdatenbank vorhanden ist erstellt wird, bleibt die Anzahl der Shards unveränderlich

shard = hash(_routing) & number_of_shards


es-Shard-Abfrageprozess

  1. Streuphase: Der Hash-Algorithmus berechnet die Shards, an die jedes Dokument gehen soll, und der koordinierende Knoten führt die Verteilung durch.
  2. Sammelphase: Der Koordinierungsknoten sammelt die von jedem Shard zurückgegebenen Ergebnisse und gibt sie an den Benutzer zurück

Es ist ein Failover

Wenn der Masterknoten des Clusters erkennt, dass ein Knoten ausgefallen ist, kopiert er seine Shard-Daten sofort auf andere Knoten. Dies ist eine Failover-Technologie.


Guess you like

Origin blog.csdn.net/delete_you/article/details/133611869