রাস্তার গড় গতি গণনা করুন [বন্ধ]


20

আমি একটি ডেটা ইঞ্জিনিয়ার জব সাক্ষাত্কারে গিয়েছিলাম। সাক্ষাত্কারকারী আমাকে একটি প্রশ্ন জিজ্ঞাসা করলেন। তিনি আমাকে কিছু পরিস্থিতি দিয়েছিলেন এবং আমাকে সেই সিস্টেমের জন্য ডেটা প্রবাহটি ডিজাইন করতে বলেছিলেন। আমি এটি সমাধান করেছি তবে তিনি আমার সমাধান পছন্দ করেন নি এবং আমি ব্যর্থ হয়েছি। কীভাবে সেই চ্যালেঞ্জটি সমাধান করবেন আপনার কাছে আরও ভাল ধারণা আছে কিনা তা আমি জানতে চাই।

প্রশ্নটি ছিল:

আমাদের সিস্টেম চারটি ডেটা স্ট্রিম গ্রহণ করে। ডেটাতে একটি গাড়ির আইডি, গতি এবং ভূ-অবস্থান সমন্বয় থাকে। প্রতিটি vihicle মিনিটে একবার তার ডেটা প্রেরণ করে। নির্দিষ্ট স্ট্রিমের সাথে নির্দিষ্ট রাস্তা বা উইহিকল বা অন্য কোনও কিছুর সাথে কোনও সংযোগ নেই। একটি ফাংশন রয়েছে যা সমন্বয় গ্রহণ করে এবং একটি রাস্তার বিভাগের নাম দেয়। আমাদের প্রতি মিনিটে প্রতি সেকেন্ডে অ্যাভারেজ গতি জানতে হবে। পরিশেষে আমরা কাফকার কাছে ফলাফল লিখতে চাই।

এখানে চিত্র বর্ণনা লিখুন

সুতরাং আমার সমাধানটি ছিল:

অক্ষাংশের 5-6 প্রথম সংখ্যাগুলি দ্বারা দ্রাঘিমাংশের দ্রাঘিমাংশের 5-6 প্রথম অঙ্কগুলিতে বিভক্ত হয়ে প্রথমে একটি বিষয়কে কাফকা ক্লাস্টারে সমস্ত ডেটা লিখতে হবে। তারপরে স্ট্রাকচার্ড স্ট্রিমিংয়ের মাধ্যমে ডেটা পড়া, প্রতিটি সারিটির জন্য সমন্বয় দ্বারা রোড বিভাগের নাম যুক্ত করা (তার জন্য একটি পূর্বনির্ধারিত ইউডিএফ রয়েছে) এবং তারপরে রাস্তার বিভাগের নাম দিয়ে ডেটা কোলেস করে।

কারণ আমি কাফকায় ডেটাগুলি সমন্বয়গুলির 5-6 প্রথম অঙ্ক অনুসারে বিভাজন করি, বিভাগের নামগুলিতে সমন্বয়গুলি অনুবাদ করার পরে, সঠিক পার্টিশনে প্রচুর ডেটা স্থানান্তর করার দরকার নেই এবং তাই আমি কোলেস () ক্রিয়াকলাপটি গ্রহণ করতে পারি এটি পুরো বদলে যায় না।

তারপরে নির্বাহকের জন্য গড় গতি গণনা করা হচ্ছে।

পুরো প্রক্রিয়াটি প্রতি 5 মিনিটে ঘটবে এবং আমরা চূড়ান্ত কাফকা সিঙ্কে ডেটা অ্যাপেন্ড মোডে লিখব।

এখানে চিত্র বর্ণনা লিখুন

সুতরাং আবারও, সাক্ষাত্কারটি আমার সমাধান পছন্দ করেনি। কেউ কীভাবে এটির উন্নতি করতে পারে বা সম্পূর্ণ আলাদা এবং আরও ভাল ধারণা দিতে পারে?


সেই ব্যক্তিকে জিজ্ঞাসা করা কি ভাল হবে না যা তিনি ঠিক পছন্দ করেন নি?
জিনো পেন

আমি মনে করি এটি দীর্ঘস্থায়ী দ্বারা বিভাজন করা খারাপ ধারণা a কিছুটা আলাদা স্থানাঙ্ক হিসাবে প্রতিটি লেনের জন্য ডেটা পয়েন্টের প্রতিবেদন করা হবে না?
ওয়েববার

@ ওয়েবার তাই আমি কেবল কয়েকটি অঙ্ক নিয়ে থাকি, সুতরাং অবস্থানটি অনন্য নয় তবে কোনও রাস্তার অংশের আকারের তুলনায় অপেক্ষাকৃত।
অ্যালন

উত্তর:


6

আমি এই প্রশ্নটি খুব আকর্ষণীয় এবং এটির চেষ্টা করে দেখেছি found

আমি আরও মূল্যায়ন হিসাবে, আপনার প্রচেষ্টা নিজেই ভাল, নিম্নলিখিত ব্যতীত:

অক্ষাংশের 5-6 প্রথম সংখ্যা দ্বারা বিভাজনটি দ্রাঘিমাংশের 5-6 প্রথম অঙ্কগুলিতে সংক্ষিপ্ত হয়ে যায়

অক্ষাংশ এবং দ্রাঘিমাংশের উপর ভিত্তি করে আপনার যদি ইতিমধ্যে রাস্তা বিভাগের আইডি / নাম পাওয়ার জন্য কোনও পদ্ধতি থাকে তবে প্রথমে সেই পদ্ধতিটি কল করে প্রথমে ডেটা ভাগ করার জন্য রোড বিভাগের আইডি / নাম ব্যবহার করবেন না কেন?

এবং তারপরে, সবকিছু বেশ সহজ, তাই টপোলজি হবে

Merge all four streams ->
Select key as the road section id/name ->
Group the stream by Key -> 
Use time windowed aggregation for the given time ->
Materialize it to a store. 

(আরও বিস্তারিত ব্যাখ্যা নীচের কোডে মন্তব্যে পাওয়া যাবে anything কিছু অস্পষ্ট কিনা তা জিজ্ঞাসা করুন)

আমি এই উত্তরটির শেষে কোডটি যুক্ত করেছি, দয়া করে নোট করুন যে গড়ের পরিবর্তে আমি যোগফলটি প্রদর্শন করা সহজ হিসাবে ব্যবহার করেছি। কিছু অতিরিক্ত ডেটা সঞ্চয় করে গড় করা সম্ভব।

আমি মন্তব্যে উত্তর বিস্তারিত করেছি। নীচে কোড থেকে উত্পন্ন টপোলজি চিত্রটি দেওয়া হয়েছে ( https://zz85.github.io/kafka-streams-viz/ কে ধন্যবাদ )

টোপোলজি:

টপোলজি ডায়াগ্রাম

    import org.apache.kafka.common.serialization.Serdes;
    import org.apache.kafka.streams.KafkaStreams;
    import org.apache.kafka.streams.StreamsBuilder;
    import org.apache.kafka.streams.StreamsConfig;
    import org.apache.kafka.streams.Topology;
    import org.apache.kafka.streams.kstream.KStream;
    import org.apache.kafka.streams.kstream.Materialized;
    import org.apache.kafka.streams.kstream.TimeWindows;
    import org.apache.kafka.streams.state.Stores;
    import org.apache.kafka.streams.state.WindowBytesStoreSupplier;

    import java.util.Arrays;
    import java.util.List;
    import java.util.Properties;
    import java.util.concurrent.CountDownLatch;

    public class VehicleStream {
        // 5 minutes aggregation window
        private static final long AGGREGATION_WINDOW = 5 * 50 * 1000L;

        public static void main(String[] args) throws Exception {
            Properties properties = new Properties();

            // Setting configs, change accordingly
            properties.put(StreamsConfig.APPLICATION_ID_CONFIG, "vehicle.stream.app");
            properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092,kafka2:19092");
            properties.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
            properties.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());

            // initializing  a streambuilder for building topology.
            final StreamsBuilder builder = new StreamsBuilder();

            // Our initial 4 streams.
            List<String> streamInputTopics = Arrays.asList(
                    "vehicle.stream1", "vehicle.stream2",
                    "vehicle.stream3", "vehicle.stream4"
            );
            /*
             * Since there is no connection between a specific stream
             * to a specific road or vehicle or anything else,
             * we can take all four streams as a single stream
             */
            KStream<String, String> source = builder.stream(streamInputTopics);

            /*
             * The initial key is unimportant (which can be ignored),
             * Instead, we will be using the section name/id as key.
             * Data will contain comma separated values in following format.
             * VehicleId,Speed,Latitude,Longitude
             */
            WindowBytesStoreSupplier windowSpeedStore = Stores.persistentWindowStore(
                    "windowSpeedStore",
                    AGGREGATION_WINDOW,
                    2, 10, true
            );
            source
                    .peek((k, v) -> printValues("Initial", k, v))
                    // First, we rekey the stream based on the road section.
                    .selectKey(VehicleStream::selectKeyAsRoadSection)
                    .peek((k, v) -> printValues("After rekey", k, v))
                    .groupByKey()
                    .windowedBy(TimeWindows.of(AGGREGATION_WINDOW))
                    .aggregate(
                            () -> "0.0", // Initialize
                            /*
                             * I'm using summing here for the aggregation as that's easier.
                             * It can be converted to average by storing extra details on number of records, etc..
                             */
                            (k, v, previousSpeed) ->  // Aggregator (summing speed)
                                    String.valueOf(
                                            Double.parseDouble(previousSpeed) +
                                                    VehicleSpeed.getVehicleSpeed(v).speed
                                    ),
                            Materialized.as(windowSpeedStore)
                    );
            // generating the topology
            final Topology topology = builder.build();
            System.out.print(topology.describe());

            // constructing a streams client with the properties and topology
            final KafkaStreams streams = new KafkaStreams(topology, properties);
            final CountDownLatch latch = new CountDownLatch(1);

            // attaching shutdown handler
            Runtime.getRuntime().addShutdownHook(new Thread("streams-shutdown-hook") {
                @Override
                public void run() {
                    streams.close();
                    latch.countDown();
                }
            });
            try {
                streams.start();
                latch.await();
            } catch (Throwable e) {
                System.exit(1);
            }
            System.exit(0);
        }


        private static void printValues(String message, String key, Object value) {
            System.out.printf("===%s=== key: %s value: %s%n", message, key, value.toString());
        }

        private static String selectKeyAsRoadSection(String key, String speedValue) {
            // Would make more sense when it's the section id, rather than a name.
            return coordinateToRoadSection(
                    VehicleSpeed.getVehicleSpeed(speedValue).latitude,
                    VehicleSpeed.getVehicleSpeed(speedValue).longitude
            );
        }

        private static String coordinateToRoadSection(String latitude, String longitude) {
            // Dummy function
            return "Area 51";
        }

        public static class VehicleSpeed {
            public String vehicleId;
            public double speed;
            public String latitude;
            public String longitude;

            public static VehicleSpeed getVehicleSpeed(String data) {
                return new VehicleSpeed(data);
            }

            public VehicleSpeed(String data) {
                String[] dataArray = data.split(",");
                this.vehicleId = dataArray[0];
                this.speed = Double.parseDouble(dataArray[1]);
                this.latitude = dataArray[2];
                this.longitude = dataArray[3];
            }

            @Override
            public String toString() {
                return String.format("veh: %s, speed: %f, latlong : %s,%s", vehicleId, speed, latitude, longitude);
            }
        }
    }

সমস্ত স্ট্রিমগুলি মার্জ করা কি কোনও খারাপ ধারণা নয়? এটি আপনার ডেটা প্রবাহের জন্য বাধা হয়ে দাঁড়াতে পারে। আপনার সিস্টেমটি বাড়ার সাথে সাথে আপনি আরও এবং আরও বেশি ইনপুট স্ট্রিমগুলি পেতে শুরু করলে কী হবে? এটি কি স্কেলেবল হবে?
wypul

@ উইপুল> সমস্ত স্ট্রিমগুলিকে একত্রিত করার কোনও খারাপ ধারণা নেই? -> আমার মনে হয় না। কাফকার মধ্যে সমান্তরালতা স্ট্রিমের মাধ্যমে অর্জিত হয় না, তবে পার্টিশন (এবং কার্যগুলি), থ্রেডিং ইত্যাদির মাধ্যমে স্ট্রিমগুলি ডেটা গ্রুপ করার উপায় way > এটি কি স্কেলেবল হবে? -> হ্যাঁ যেহেতু আমরা রাস্তা বিভাগগুলি ধরে রেখেছি এবং ধরে নিচ্ছি যে রাস্তা বিভাগগুলি মোটামুটি বিতরণ করা হয়েছে, তাই আমরা বিভিন্ন ধারকগুলিতে স্ট্রিমটিকে প্যারালাইলি প্রক্রিয়া করার জন্য এই বিষয়গুলির পার্টিশনের সংখ্যা বাড়াতে পারি। প্রতিলিপি জুড়ে লোড বিতরণ করতে আমরা রাস্তা বিভাগের উপর ভিত্তি করে একটি ভাল পার্টিশনিং অ্যালগরিদম ব্যবহার করতে পারি।
ইরশাদ পিআই

1

এই জাতীয় সমস্যাটি সহজ বলে মনে হচ্ছে এবং প্রদত্ত সমাধানগুলি ইতিমধ্যে প্রচুর অর্থবোধ করে। আমি ভাবছি যে সাক্ষাত্কারটি আপনি যে সমাধানটির দিকে মনোনিবেশ করেছেন সেটির নকশা এবং কার্য সম্পাদন বা ফলাফলের যথার্থতা সম্পর্কে উদ্বিগ্ন ছিলেন কি না। যেহেতু অন্যরা কোড, ডিজাইন এবং কার্য সম্পাদনের দিকে মনোনিবেশ করেছে আমি যথার্থতার উপর নির্ভর করব।

স্ট্রিমিং সলিউশন

ডেটা প্রবাহিত হওয়ায় আমরা কোনও রাস্তার গড় গতি সম্পর্কে মোটামুটি অনুমান দিতে পারি। এই অনুমানটি ভিড় সনাক্তকরণে সহায়ক হবে তবে গতির সীমা নির্ধারণে এটি বন্ধ থাকবে।

  1. সমস্ত 4 টি স্ট্রিমের ডেটা একত্রিত করুন।
  2. 5 মিনিটের মধ্যে সমস্ত 4 টি স্ট্রিম থেকে ডেটা ক্যাপচার করতে 5 মিনিটের একটি উইন্ডো তৈরি করুন।
  3. রাস্তার নাম এবং শহরের নাম পেতে স্থানাঙ্কগুলিতে ইউডিএফ প্রয়োগ করুন। রাস্তার নামগুলি প্রায়শই শহরগুলিতে সদৃশ হয়, তাই আমরা শহরের নাম + রাস্তার নাম কী হিসাবে ব্যবহার করব।
  4. একটি সিনট্যাক্সের মতো গড় গতি গণনা করুন -

    vehicle_street_speed
      .groupBy($"city_name_street_name")
      .agg(
        avg($"speed").as("avg_speed")
      )

5. write the result to the Kafka Topic

ব্যাচের সমাধান

নমুনার আকার ছোট হওয়ায় এই অনুমানটি বন্ধ থাকবে। গতির সীমাটি আরও সঠিকভাবে নির্ধারণ করতে আমাদের পুরো মাস / ত্রৈমাসিক / বছরের ডেটাতে একটি ব্যাচ প্রসেসিংয়ের প্রয়োজন হবে।

  1. ডেটা হ্রদ (বা কাফকা বিষয়) থেকে এক বছরের ডেটা পড়ুন

  2. রাস্তার নাম এবং শহরের নাম পেতে স্থানাঙ্কগুলিতে ইউডিএফ প্রয়োগ করুন।

  3. একটি সিনট্যাক্সের মতো গড় গতি গণনা করুন -


    vehicle_street_speed
      .groupBy($"city_name_street_name")
      .agg(
        avg($"speed").as("avg_speed")
      )

  1. তথ্য লেকের ফলাফল লিখুন।

এই আরও সঠিক গতির সীমাটির ভিত্তিতে আমরা স্ট্রিমিং অ্যাপ্লিকেশনে ধীর ট্র্যাফিকের পূর্বাভাস দিতে পারি।


1

আপনার বিভাজন কৌশলটি নিয়ে আমি কয়েকটি সমস্যা দেখছি:

  • আপনি যখন বলছেন যে আপনি ল্যাট লম্বা প্রথম 5-6 সংখ্যার উপর ভিত্তি করে আপনার ডেটা বিভাজন করতে যাচ্ছেন, আপনি কাফকা পার্টিশনের সংখ্যা আগে নির্ধারণ করতে পারবেন না। কিছু রাস্তার বিভাগগুলির জন্য আপনার কাছে স্কিউ ডেটা থাকবে যা আপনি অন্যদের তুলনায় একটি উচ্চ ভলিউম পর্যবেক্ষণ করবেন।

  • এবং আপনার কী সংমিশ্রণটি যেভাবেই হোক একই বিভাজনে একই রোড বিভাগের ডেটার গ্যারান্টি দেয় না এবং তাই আপনি নিশ্চিত হতে পারবেন না যে সেখানে পরিবর্তন হবে না।

আইএমও প্রদত্ত তথ্য পুরো ডেটা পাইপলাইন ডিজাইনের জন্য পর্যাপ্ত নয়। কারণ পাইপলাইনটি ডিজাইন করার সময় আপনি কীভাবে আপনার ডেটা ভাগ করবেন তা গুরুত্বপূর্ণ ভূমিকা পালন করে। যানবাহনের সংখ্যা, ইনপুট ডেটা স্ট্রিমের আকার, স্ট্রিমের সংখ্যা স্থির করা আছে বা ভবিষ্যতে কী এটি বাড়তে পারে তার মতো আপনার যে ডেটা আপনি পাচ্ছেন সে সম্পর্কে আপনার আরও জিজ্ঞাসা করা উচিত? আপনি যে ইনপুট ডেটা স্ট্রিমগুলি পাচ্ছেন তা কি কাফকা স্ট্রিম? 5 মিনিটে আপনি কত ডেটা পাবেন?

  • এখন ধরে নেওয়া যাক আপনার কাছে কাফকা বা 4 টি পার্টিশনে 4 টি বিষয়ে লিখিত 4 টি স্ট্রিম রয়েছে এবং আপনার কোনও নির্দিষ্ট কী নেই তবে আপনার ডেটা কিছু ডেটা সেন্টার কী এর উপর ভিত্তি করে বিভক্ত করা হয়েছে বা এটি হ্যাশ পার্টিশনযুক্ত। যদি তা না হয় তবে এটি অন্য কাফকা প্রবাহে ডে-ডুপ্লিকেট করার পরিবর্তে এবং পার্টিশন করার পরিবর্তে ডেটা সাইডে করা উচিত।
  • আপনি যদি বিভিন্ন ডেটা সেন্টারে ডেটা পেয়ে থাকেন তবে আপনাকে একটি ক্লাস্টারে ডেটা আনতে হবে এবং সেই উদ্দেশ্যে আপনি কাফকা মিরর মেকার বা অনুরূপ কিছু ব্যবহার করতে পারেন।
  • আপনার কাছে একটি ক্লাস্টারে সমস্ত ডেটা থাকার পরে আপনি সেখানে একটি কাঠামোগত স্ট্রিমিং কাজ চালাতে পারেন এবং আপনার প্রয়োজনের ভিত্তিতে 5 মিনিটের ট্রিগার ব্যবধান এবং ওয়াটারমার্ক দিয়ে।
  • গড় গণনা করতে এবং অনেকগুলি এলোমেলো এড়াতে আপনি গ্রুপবিয়ের পরিবর্তে mapValuesএবং এর reduceByKeyপরিবর্তে একটি সংমিশ্রণ ব্যবহার করতে পারেন । পড়ুন এই
  • প্রসেসিংয়ের পরে আপনি কাফকা সিঙ্কে ডেটা লিখতে পারেন।

মানচিত্রের মানগুলি এবং কমিয়ে দেওয়া উচ্চ-স্তরের আরডিডির অন্তর্ভুক্ত। ক্যাটালিস্ট কি আমি গোষ্ঠীবদ্ধ হয়ে গড় গণনা করার সময় সবচেয়ে কার্যকর আরডিডি উত্পন্ন করার পক্ষে যথেষ্ট স্মার্ট নন?
অ্যালোন

@ অ্যালোন ক্যাটালিস্ট অবশ্যই আপনার ক্যোয়ারি চালানোর জন্য সেরা পরিকল্পনাটি বের করতে সক্ষম হবে তবে আপনি যদি গ্রুপবাই ব্যবহার করেন তবে একই কী সহ ডেটা প্রথমে একই পার্টিশনে স্থানান্তরিত হবে এবং তারপরে সামগ্রিক অপারেশন প্রয়োগ করবে। mapValuesএবং reduceByপ্রকৃতপক্ষে নিম্ন-স্তরের আরডিডি-র অন্তর্ভুক্ত তবে এটি এখনও এই পরিস্থিতিতে আরও ভাল পারফর্ম করবে কারণ এটি প্রথমে পার্টিশন অনুযায়ী সামগ্রিকভাবে সঞ্চার করবে এবং তারপরে পরিবর্তন হবে।
উইপুল

0

এই সমাধানটি সহ আমি যে প্রধান সমস্যাগুলি দেখছি তা হ'ল:

  • মানচিত্রের 6 ডিজিটের স্কোয়ারের কিনারায় থাকা রাস্তা বিভাগগুলিতে একাধিক বিষয়ের পার্টিশনগুলিতে ডেটা থাকবে এবং একাধিক গড় গতি থাকবে।
  • আপনার কাফকা পার্টিশনের জন্য ইনজেশন ডেটার আকার ভারসাম্যহীন হতে পারে (শহর বনাম মরুভূমি)। প্রথম আইডি গাড়ীর আইডি দ্বারা পার্টিশন করা ভাল ধারণা আইএমও হতে পারে।
  • নিশ্চিত নয় যে আমি কোলেসেস অংশটি অনুসরণ করেছি, তবে এটি সমস্যাযুক্ত মনে হচ্ছে।

আমি বলব যে সমাধানটি করা দরকার: কাফকা স্ট্রিম থেকে>> ইউডিএফ -> গ্রুপবিডি রোড বিভাগ -> গড় -> কাফকা প্রবাহে লিখুন read


0

আমার নকশা উপর নির্ভর করবে

  1. রাস্তার সংখ্যা
  2. যানবাহন সংখ্যা
  3. স্থানাঙ্ক থেকে রাস্তার গণনা ব্যয়

আমি যদি কোনও সংখ্যার জন্য স্কেল করতে চাই তবে নকশাটি দেখতে এটির মতো লাগবে এখানে চিত্র বর্ণনা লিখুন

এই নকশায় উদ্বেগগুলি অতিক্রম করুন -

  1. ইনপুট স্ট্রিমগুলির টেকসই অবস্থা বজায় রাখুন (যদি ইনপুট কাফকা হয়, আমরা কাফকার সাথে বা বাহ্যিকভাবে অফসেটগুলি সঞ্চয় করতে পারি)
  2. পর্যায়ক্রমে চেকপয়েন্টটি বাহ্যিক সিস্টেমে জানায় (আমি ফ্লিঙ্কে অ্যাসিঙ্ক চেকপয়েন্ট বাধা ব্যবহার করা পছন্দ করি )

এই নকশায় কিছু ব্যবহারিক বর্ধন সম্ভব -

  1. রাস্তার উপর ভিত্তি করে সম্ভব হলে রোড সেকশন ম্যাপিংয়ের কাজ করা হচ্ছে C
  2. মিস পিংস হ্যান্ডলিং (অনুশীলনে প্রতিটি পিং পাওয়া যায় না)
  3. রাস্তার বক্রতা বিবেচনায় নেওয়া (ভারতে এবং উচ্চতায় অ্যাকাউন্টে)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.