Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(427)

Side by Side Diff: components/autofill/core/browser/form_structure.cc

Issue 2870163003: Log Autofill.Quality.*.ByFieldType by predicted type for unknown data. (Closed)
Patch Set: remove confusing 'units' from histograms.xml Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/autofill/core/browser/field_types.h ('k') | tools/metrics/histograms/enums.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/core/browser/form_structure.h" 5 #include "components/autofill/core/browser/form_structure.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <map> 10 #include <map>
(...skipping 29 matching lines...) Expand all
40 #include "components/rappor/rappor_service_impl.h" 40 #include "components/rappor/rappor_service_impl.h"
41 #include "components/ukm/public/ukm_recorder.h" 41 #include "components/ukm/public/ukm_recorder.h"
42 42
43 namespace autofill { 43 namespace autofill {
44 namespace { 44 namespace {
45 45
46 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)"; 46 const char kClientVersion[] = "6.1.1715.1442/en (GGLL)";
47 const char kBillingMode[] = "billing"; 47 const char kBillingMode[] = "billing";
48 const char kShippingMode[] = "shipping"; 48 const char kShippingMode[] = "shipping";
49 49
50 // A form is considered to have a high prediction mismatch rate if the number of
51 // mismatches exceeds this threshold.
52 const int kNumberOfMismatchesThreshold = 3;
53
54 // Only removing common name prefixes if we have a minimum number of fields and 50 // Only removing common name prefixes if we have a minimum number of fields and
55 // a minimum prefix length. These values are chosen to avoid cases such as two 51 // a minimum prefix length. These values are chosen to avoid cases such as two
56 // fields with "address1" and "address2" and be effective against web frameworks 52 // fields with "address1" and "address2" and be effective against web frameworks
57 // which prepend prefixes such as "ctl01$ctl00$MainContentRegion$" on all 53 // which prepend prefixes such as "ctl01$ctl00$MainContentRegion$" on all
58 // fields. 54 // fields.
59 const int kCommonNamePrefixRemovalFieldThreshold = 3; 55 const int kCommonNamePrefixRemovalFieldThreshold = 3;
60 const int kMinCommonNamePrefixLength = 16; 56 const int kMinCommonNamePrefixLength = 16;
61 57
62 // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to 58 // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to
63 // |available_field_types| and returns the hex representation as a string. 59 // |available_field_types| and returns the hex representation as a string.
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 690
695 void FormStructure::LogQualityMetrics( 691 void FormStructure::LogQualityMetrics(
696 const base::TimeTicks& load_time, 692 const base::TimeTicks& load_time,
697 const base::TimeTicks& interaction_time, 693 const base::TimeTicks& interaction_time,
698 const base::TimeTicks& submission_time, 694 const base::TimeTicks& submission_time,
699 rappor::RapporServiceImpl* rappor_service, 695 rappor::RapporServiceImpl* rappor_service,
700 AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger, 696 AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger,
701 bool did_show_suggestions, 697 bool did_show_suggestions,
702 bool observed_submission) const { 698 bool observed_submission) const {
703 size_t num_detected_field_types = 0; 699 size_t num_detected_field_types = 0;
704 size_t num_server_mismatches = 0;
705 size_t num_heuristic_mismatches = 0;
706 size_t num_edited_autofilled_fields = 0; 700 size_t num_edited_autofilled_fields = 0;
707 bool did_autofill_all_possible_fields = true; 701 bool did_autofill_all_possible_fields = true;
708 bool did_autofill_some_possible_fields = false; 702 bool did_autofill_some_possible_fields = false;
709 703
710 // Determine the correct suffix for the metric, depending on whether or 704 // Determine the correct suffix for the metric, depending on whether or
711 // not a submission was observed. 705 // not a submission was observed.
712 const AutofillMetrics::QualityMetricType metric_type = 706 const AutofillMetrics::QualityMetricType metric_type =
713 observed_submission ? AutofillMetrics::TYPE_SUBMISSION 707 observed_submission ? AutofillMetrics::TYPE_SUBMISSION
714 : AutofillMetrics::TYPE_NO_SUBMISSION; 708 : AutofillMetrics::TYPE_NO_SUBMISSION;
715 709
(...skipping 18 matching lines...) Expand all
734 // Aliases for the field types predicted by heuristics, server and overall. 728 // Aliases for the field types predicted by heuristics, server and overall.
735 ServerFieldType heuristic_type = 729 ServerFieldType heuristic_type =
736 AutofillType(field->heuristic_type()).GetStorableType(); 730 AutofillType(field->heuristic_type()).GetStorableType();
737 ServerFieldType server_type = 731 ServerFieldType server_type =
738 AutofillType(field->server_type()).GetStorableType(); 732 AutofillType(field->server_type()).GetStorableType();
739 ServerFieldType predicted_type = field->Type().GetStorableType(); 733 ServerFieldType predicted_type = field->Type().GetStorableType();
740 734
741 const ServerFieldTypeSet& field_types = field->possible_types(); 735 const ServerFieldTypeSet& field_types = field->possible_types();
742 DCHECK(!field_types.empty()); 736 DCHECK(!field_types.empty());
743 737
744 // If the field data is empty, or unrecognized, log whether or not autofill 738 AutofillMetrics::LogHeuristicPredictionQualityMetrics(
745 // predicted that it would be populated with an autofillable data type. 739 field_types, heuristic_type, metric_type);
746 bool has_empty_data = field_types.count(EMPTY_TYPE) != 0; 740 AutofillMetrics::LogServerPredictionQualityMetrics(field_types, server_type,
747 bool has_unrecognized_data = field_types.count(UNKNOWN_TYPE) != 0; 741 metric_type);
748 if (has_empty_data || has_unrecognized_data) { 742 AutofillMetrics::LogOverallPredictionQualityMetrics(
749 AutofillMetrics::FieldTypeQualityMetric match_empty_or_unknown = 743 field_types, predicted_type, metric_type);
750 has_empty_data ? AutofillMetrics::TYPE_MATCH_EMPTY 744
751 : AutofillMetrics::TYPE_MATCH_UNKNOWN; 745 if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE))
752 AutofillMetrics::FieldTypeQualityMetric mismatch_empty_or_unknown =
753 has_empty_data ? AutofillMetrics::TYPE_MISMATCH_EMPTY
754 : AutofillMetrics::TYPE_MISMATCH_UNKNOWN;
755 ServerFieldType field_type = has_empty_data ? EMPTY_TYPE : UNKNOWN_TYPE;
756 AutofillMetrics::LogHeuristicTypePrediction(
757 (heuristic_type == UNKNOWN_TYPE ? match_empty_or_unknown
758 : mismatch_empty_or_unknown),
759 field_type, metric_type);
760 AutofillMetrics::LogServerTypePrediction(
761 (server_type == NO_SERVER_DATA ? match_empty_or_unknown
762 : mismatch_empty_or_unknown),
763 field_type, metric_type);
764 AutofillMetrics::LogOverallTypePrediction(
765 (predicted_type == UNKNOWN_TYPE ? match_empty_or_unknown
766 : mismatch_empty_or_unknown),
767 field_type, metric_type);
768 continue; 746 continue;
769 }
770 747
771 ++num_detected_field_types; 748 ++num_detected_field_types;
772 if (field->is_autofilled) 749 if (field->is_autofilled)
773 did_autofill_some_possible_fields = true; 750 did_autofill_some_possible_fields = true;
774 else 751 else
775 did_autofill_all_possible_fields = false; 752 did_autofill_all_possible_fields = false;
776
777 // Collapse field types that Chrome treats as identical, e.g. home and
778 // billing address fields.
779 ServerFieldTypeSet collapsed_field_types;
780 for (const auto& it : field_types) {
781 // Since we currently only support US phone numbers, the (city code + main
782 // digits) number is almost always identical to the whole phone number.
783 // TODO(isherman): Improve this logic once we add support for
784 // international numbers.
785 if (it == PHONE_HOME_CITY_AND_NUMBER)
786 collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
787 else
788 collapsed_field_types.insert(AutofillType(it).GetStorableType());
789 }
790
791 // Capture the field's type, if it is unambiguous.
792 ServerFieldType field_type = UNKNOWN_TYPE;
793 if (collapsed_field_types.size() == 1)
794 field_type = *collapsed_field_types.begin();
795
796 // Log heuristic, server, and overall type quality metrics.
797 if (heuristic_type == UNKNOWN_TYPE) {
798 AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN,
799 field_type, metric_type);
800 } else if (field_types.count(heuristic_type)) {
801 AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_MATCH,
802 field_type, metric_type);
803 } else {
804 ++num_heuristic_mismatches;
805 AutofillMetrics::LogHeuristicTypePrediction(
806 AutofillMetrics::TYPE_MISMATCH, field_type, metric_type);
807 }
808
809 if (server_type == NO_SERVER_DATA) {
810 AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_UNKNOWN,
811 field_type, metric_type);
812 } else if (field_types.count(server_type)) {
813 AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_MATCH,
814 field_type, metric_type);
815 } else {
816 ++num_server_mismatches;
817 AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_MISMATCH,
818 field_type, metric_type);
819 }
820
821 if (predicted_type == UNKNOWN_TYPE) {
822 AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_UNKNOWN,
823 field_type, metric_type);
824 } else if (field_types.count(predicted_type)) {
825 AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MATCH,
826 field_type, metric_type);
827 } else {
828 AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MISMATCH,
829 field_type, metric_type);
830 }
831 } 753 }
832 754
833 AutofillMetrics::LogNumberOfEditedAutofilledFields( 755 AutofillMetrics::LogNumberOfEditedAutofilledFields(
834 num_edited_autofilled_fields, observed_submission); 756 num_edited_autofilled_fields, observed_submission);
835 757
836 // We log "submission" and duration metrics if we are here after observing a 758 // We log "submission" and duration metrics if we are here after observing a
837 // submission event. 759 // submission event.
838 if (observed_submission) { 760 if (observed_submission) {
839 AutofillMetrics::AutofillFormSubmittedState state; 761 AutofillMetrics::AutofillFormSubmittedState state;
840 if (num_detected_field_types < kRequiredFieldsForPredictionRoutines) { 762 if (num_detected_field_types < kRequiredFieldsForPredictionRoutines) {
841 state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA; 763 state = AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA;
842 } else { 764 } else {
843 if (did_autofill_all_possible_fields) { 765 if (did_autofill_all_possible_fields) {
844 state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL; 766 state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL;
845 } else if (did_autofill_some_possible_fields) { 767 } else if (did_autofill_some_possible_fields) {
846 state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME; 768 state = AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME;
847 } else if (!did_show_suggestions) { 769 } else if (!did_show_suggestions) {
848 state = AutofillMetrics:: 770 state = AutofillMetrics::
849 FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS; 771 FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS;
850 } else { 772 } else {
851 state = 773 state =
852 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS; 774 AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS;
853 } 775 }
854 776
855 // Log some RAPPOR metrics for problematic cases.
856 if (num_server_mismatches >= kNumberOfMismatchesThreshold) {
857 rappor::SampleDomainAndRegistryFromGURL(
858 rappor_service, "Autofill.HighNumberOfServerMismatches",
859 source_url_);
860 }
861 if (num_heuristic_mismatches >= kNumberOfMismatchesThreshold) {
862 rappor::SampleDomainAndRegistryFromGURL(
863 rappor_service, "Autofill.HighNumberOfHeuristicMismatches",
864 source_url_);
865 }
866
867 // Unlike the other times, the |submission_time| should always be 777 // Unlike the other times, the |submission_time| should always be
868 // available. 778 // available.
869 DCHECK(!submission_time.is_null()); 779 DCHECK(!submission_time.is_null());
870 780
871 // The |load_time| might be unset, in the case that the form was 781 // The |load_time| might be unset, in the case that the form was
872 // dynamically 782 // dynamically
873 // added to the DOM. 783 // added to the DOM.
874 if (!load_time.is_null()) { 784 if (!load_time.is_null()) {
875 // Submission should always chronologically follow form load. 785 // Submission should always chronologically follow form load.
876 DCHECK(submission_time > load_time); 786 DCHECK(submission_time > load_time);
(...skipping 20 matching lines...) Expand all
897 } 807 }
898 } 808 }
899 if (form_interactions_ukm_logger->url() != source_url()) 809 if (form_interactions_ukm_logger->url() != source_url())
900 form_interactions_ukm_logger->UpdateSourceURL(source_url()); 810 form_interactions_ukm_logger->UpdateSourceURL(source_url());
901 AutofillMetrics::LogAutofillFormSubmittedState( 811 AutofillMetrics::LogAutofillFormSubmittedState(
902 state, form_interactions_ukm_logger); 812 state, form_interactions_ukm_logger);
903 } 813 }
904 } 814 }
905 815
906 void FormStructure::LogQualityMetricsBasedOnAutocomplete() const { 816 void FormStructure::LogQualityMetricsBasedOnAutocomplete() const {
817 const AutofillMetrics::QualityMetricType metric_type =
818 AutofillMetrics::TYPE_AUTOCOMPLETE_BASED;
907 for (const auto& field : fields_) { 819 for (const auto& field : fields_) {
908 if (field->html_type() != HTML_TYPE_UNSPECIFIED && 820 if (field->html_type() != HTML_TYPE_UNSPECIFIED &&
909 field->html_type() != HTML_TYPE_UNRECOGNIZED) { 821 field->html_type() != HTML_TYPE_UNRECOGNIZED) {
910 // The type inferred by the autocomplete attribute. 822 // The type inferred by the autocomplete attribute.
911 AutofillType type(field->html_type(), field->html_mode()); 823 ServerFieldTypeSet actual_field_type_set{
912 ServerFieldType actual_field_type = type.GetStorableType(); 824 AutofillType(field->html_type(), field->html_mode())
825 .GetStorableType()};
913 826
914 const AutofillMetrics::QualityMetricType metric_type = 827 AutofillMetrics::LogHeuristicPredictionQualityMetrics(
915 AutofillMetrics::TYPE_AUTOCOMPLETE_BASED; 828 actual_field_type_set, field->heuristic_type(), metric_type);
916 // Log the quality of our heuristics predictions. 829 AutofillMetrics::LogServerPredictionQualityMetrics(
917 if (field->heuristic_type() == UNKNOWN_TYPE) { 830 actual_field_type_set, field->server_type(), metric_type);
918 AutofillMetrics::LogHeuristicTypePrediction(
919 AutofillMetrics::TYPE_UNKNOWN, actual_field_type, metric_type);
920 } else if (field->heuristic_type() == actual_field_type) {
921 AutofillMetrics::LogHeuristicTypePrediction(
922 AutofillMetrics::TYPE_MATCH, actual_field_type, metric_type);
923 } else {
924 AutofillMetrics::LogHeuristicTypePrediction(
925 AutofillMetrics::TYPE_MISMATCH, actual_field_type, metric_type);
926 }
927
928 // Log the quality of our server predictions.
929 if (field->server_type() == NO_SERVER_DATA) {
930 AutofillMetrics::LogServerTypePrediction(
931 AutofillMetrics::TYPE_UNKNOWN, actual_field_type, metric_type);
932 } else if (field->server_type() == actual_field_type) {
933 AutofillMetrics::LogServerTypePrediction(
934 AutofillMetrics::TYPE_MATCH, actual_field_type, metric_type);
935 } else {
936 AutofillMetrics::LogServerTypePrediction(
937 AutofillMetrics::TYPE_MISMATCH, actual_field_type, metric_type);
938 }
939 } 831 }
940 } 832 }
941 } 833 }
942 834
943 void FormStructure::ParseFieldTypesFromAutocompleteAttributes() { 835 void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
944 const std::string kDefaultSection = "-default"; 836 const std::string kDefaultSection = "-default";
945 837
946 has_author_specified_types_ = false; 838 has_author_specified_types_ = false;
947 has_author_specified_sections_ = false; 839 has_author_specified_sections_ = false;
948 has_author_specified_upi_vpa_hint_ = false; 840 has_author_specified_upi_vpa_hint_ = false;
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after
1383 filtered_strings[0].at(prefix_len)) { 1275 filtered_strings[0].at(prefix_len)) {
1384 // Mismatch found. 1276 // Mismatch found.
1385 return filtered_strings[i].substr(0, prefix_len); 1277 return filtered_strings[i].substr(0, prefix_len);
1386 } 1278 }
1387 } 1279 }
1388 } 1280 }
1389 return filtered_strings[0]; 1281 return filtered_strings[0];
1390 } 1282 }
1391 1283
1392 } // namespace autofill 1284 } // namespace autofill
OLDNEW
« no previous file with comments | « components/autofill/core/browser/field_types.h ('k') | tools/metrics/histograms/enums.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698